Slider value indicator gets disposed if it is activated (#57535)

diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart
index 215984c..c394cce 100644
--- a/packages/flutter/lib/src/material/range_slider.dart
+++ b/packages/flutter/lib/src/material/range_slider.dart
@@ -472,6 +472,10 @@
     enableController.dispose();
     startPositionController.dispose();
     endPositionController.dispose();
+    if (overlayEntry != null) {
+      overlayEntry.remove();
+      overlayEntry = null;
+    }
     super.dispose();
   }
 
@@ -1154,6 +1158,10 @@
   }
 
   void _handleDragUpdate(DragUpdateDetails details) {
+    if (!_state.mounted) {
+      return;
+    }
+
     final double dragValue = _getValueFromGlobalPosition(details.globalPosition);
 
     // If no selection has been made yet, test for thumb selection again now
@@ -1190,7 +1198,10 @@
   }
 
   void _endInteraction() {
-    _state.overlayController.reverse();
+    if (!_state.mounted) {
+      return;
+    }
+
     if (showValueIndicator && _state.interactionTimer == null) {
       _state.valueIndicatorController.reverse();
     }
@@ -1202,6 +1213,7 @@
       }
       _active = false;
     }
+    _state.overlayController.reverse();
   }
 
   void _handleDragStart(DragStartDetails details) {
@@ -1388,22 +1400,24 @@
 
     if (shouldPaintValueIndicators) {
       _state.paintBottomValueIndicator = (PaintingContext context, Offset offset) {
-        _sliderTheme.rangeValueIndicatorShape.paint(
-          context,
-          bottomThumbCenter,
-          activationAnimation: _valueIndicatorAnimation,
-          enableAnimation: _enableAnimation,
-          isDiscrete: isDiscrete,
-          isOnTop: false,
-          labelPainter: bottomLabelPainter,
-          parentBox: this,
-          sliderTheme: _sliderTheme,
-          textDirection: _textDirection,
-          thumb: bottomThumb,
-          value: bottomValue,
-          textScaleFactor: textScaleFactor,
-          sizeWithOverflow: resolvedscreenSize,
-        );
+        if (attached) {
+          _sliderTheme.rangeValueIndicatorShape.paint(
+            context,
+            bottomThumbCenter,
+            activationAnimation: _valueIndicatorAnimation,
+            enableAnimation: _enableAnimation,
+            isDiscrete: isDiscrete,
+            isOnTop: false,
+            labelPainter: bottomLabelPainter,
+            parentBox: this,
+            sliderTheme: _sliderTheme,
+            textDirection: _textDirection,
+            thumb: bottomThumb,
+            value: bottomValue,
+            textScaleFactor: textScaleFactor,
+            sizeWithOverflow: resolvedscreenSize,
+          );
+        }
       };
     }
 
@@ -1462,22 +1476,24 @@
       }
 
       _state.paintTopValueIndicator = (PaintingContext context, Offset offset) {
-        _sliderTheme.rangeValueIndicatorShape.paint(
-          context,
-          topThumbCenter,
-          activationAnimation: _valueIndicatorAnimation,
-          enableAnimation: _enableAnimation,
-          isDiscrete: isDiscrete,
-          isOnTop: thumbDelta < innerOverflow,
-          labelPainter: topLabelPainter,
-          parentBox: this,
-          sliderTheme: _sliderTheme,
-          textDirection: _textDirection,
-          thumb: topThumb,
-          value: topValue,
-          textScaleFactor: textScaleFactor,
-          sizeWithOverflow: resolvedscreenSize,
-        );
+        if (attached) {
+          _sliderTheme.rangeValueIndicatorShape.paint(
+            context,
+            topThumbCenter,
+            activationAnimation: _valueIndicatorAnimation,
+            enableAnimation: _enableAnimation,
+            isDiscrete: isDiscrete,
+            isOnTop: thumbDelta < innerOverflow,
+            labelPainter: topLabelPainter,
+            parentBox: this,
+            sliderTheme: _sliderTheme,
+            textDirection: _textDirection,
+            thumb: topThumb,
+            value: topValue,
+            textScaleFactor: textScaleFactor,
+            sizeWithOverflow: resolvedscreenSize,
+          );
+        }
       };
     }
 
diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart
index 234b949..4498934 100644
--- a/packages/flutter/lib/src/material/slider.dart
+++ b/packages/flutter/lib/src/material/slider.dart
@@ -512,6 +512,10 @@
     valueIndicatorController.dispose();
     enableController.dispose();
     positionController.dispose();
+    if (overlayEntry != null) {
+      overlayEntry.remove();
+      overlayEntry = null;
+    }
     super.dispose();
   }
 
@@ -1238,6 +1242,10 @@
   }
 
   void _endInteraction() {
+    if (!_state.mounted) {
+      return;
+    }
+
     if (_active && _state.mounted) {
       if (onChangeEnd != null) {
         onChangeEnd(_discretize(_currentDragValue));
@@ -1255,6 +1263,10 @@
   void _handleDragStart(DragStartDetails details) => _startInteraction(details.globalPosition);
 
   void _handleDragUpdate(DragUpdateDetails details) {
+    if (!_state.mounted) {
+      return;
+    }
+
     if (isInteractive) {
       final double valueDelta = details.primaryDelta / _trackRect.width;
       switch (textDirection) {
@@ -1396,20 +1408,22 @@
     if (isInteractive && label != null && !_valueIndicatorAnimation.isDismissed) {
       if (showValueIndicator) {
         _state.paintValueIndicator = (PaintingContext context, Offset offset) {
-          _sliderTheme.valueIndicatorShape.paint(
-            context,
-            offset + thumbCenter,
-            activationAnimation: _valueIndicatorAnimation,
-            enableAnimation: _enableAnimation,
-            isDiscrete: isDiscrete,
-            labelPainter: _labelPainter,
-            parentBox: this,
-            sliderTheme: _sliderTheme,
-            textDirection: _textDirection,
-            value: _value,
-            textScaleFactor: textScaleFactor,
-            sizeWithOverflow: screenSize.isEmpty ? size : screenSize,
-          );
+          if (attached) {
+            _sliderTheme.valueIndicatorShape.paint(
+              context,
+              offset + thumbCenter,
+              activationAnimation: _valueIndicatorAnimation,
+              enableAnimation: _enableAnimation,
+              isDiscrete: isDiscrete,
+              labelPainter: _labelPainter,
+              parentBox: this,
+              sliderTheme: _sliderTheme,
+              textDirection: _textDirection,
+              value: _value,
+              textScaleFactor: textScaleFactor,
+              sizeWithOverflow: screenSize.isEmpty ? size : screenSize,
+            );
+          }
         };
       }
     }
diff --git a/packages/flutter/lib/src/material/slider_theme.dart b/packages/flutter/lib/src/material/slider_theme.dart
index 2b7fc8a..3b0c18d 100644
--- a/packages/flutter/lib/src/material/slider_theme.dart
+++ b/packages/flutter/lib/src/material/slider_theme.dart
@@ -2791,6 +2791,7 @@
     double scale,
   }) {
     assert(!sizeWithOverflow.isEmpty);
+
     const double edgePadding = 8.0;
     final double rectangleWidth = _upperRectangleWidth(labelPainter, scale, textScaleFactor);
     /// Value indicator draws on the Overlay and by using the global Offset
diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart
index 28380bc..a92b64e 100644
--- a/packages/flutter/test/material/range_slider_test.dart
+++ b/packages/flutter/test/material/range_slider_test.dart
@@ -1338,6 +1338,101 @@
 
   });
 
+  testWidgets('Range Slider removes value indicator from overlay if Slider gets disposed without value indicator animation completing.', (WidgetTester tester) async {
+    final ThemeData theme = _buildTheme();
+    final SliderThemeData sliderTheme = theme.sliderTheme;
+    RangeValues values = const RangeValues(0.5, 0.75);
+
+    Widget buildApp({
+      Color activeColor,
+      Color inactiveColor,
+      int divisions,
+      bool enabled = true,
+    }) {
+      final ValueChanged<RangeValues> onChanged = (RangeValues newValues) {
+        values = newValues;
+      };
+      return MaterialApp(
+        home: Directionality(
+          textDirection: TextDirection.ltr,
+          child: Material(
+            child: Navigator(onGenerateRoute: (RouteSettings settings) {
+              return MaterialPageRoute<void>(builder: (BuildContext context) {
+                return Column(
+                  children: <Widget>[
+                    Theme(
+                      data: theme,
+                      child: RangeSlider(
+                        values: values,
+                        labels: RangeLabels(values.start.toStringAsFixed(2),
+                            values.end.toStringAsFixed(2)),
+                        divisions: divisions,
+                        onChanged: onChanged,
+                      ),
+                    ),
+                    RaisedButton(
+                      child: const Text('Next'),
+                      onPressed: () {
+                        Navigator.of(context).pushReplacement(
+                          MaterialPageRoute<void>(
+                            builder: (BuildContext context) {
+                              return RaisedButton(
+                                child: const Text('Inner page'),
+                                onPressed: () => Navigator.of(context).pop(),
+                              );
+                            },
+                          ),
+                        );
+                      },
+                    ),
+                  ],
+                );
+              });
+            }),
+          ),
+        ),
+      );
+    }
+
+    await tester.pumpWidget(buildApp(divisions: 3));
+
+    /// The value indicator is added to the overlay when it is clicked or dragged.
+    /// Because both of these gestures are occurring then it adds same value indicator
+    /// twice into the overlay.
+    final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay));
+    final Offset topRight = tester.getTopRight(find.byType(RangeSlider)).translate(-24, 0);
+    final TestGesture gesture = await tester.startGesture(topRight);
+    // Wait for value indicator animation to finish.
+    await tester.pumpAndSettle();
+
+    expect(find.byType(RangeSlider), isNotNull);
+    expect(
+      valueIndicatorBox,
+      paints
+        ..rrect(color: sliderTheme.inactiveTrackColor)
+        ..rect(color: sliderTheme.activeTrackColor)
+        ..rrect(color: sliderTheme.inactiveTrackColor),
+    );
+
+    await tester.tap(find.text('Next'));
+    await tester.pumpAndSettle();
+
+    expect(find.byType(RangeSlider), findsNothing);
+    expect(
+      valueIndicatorBox,
+      isNot(
+         paints
+           ..rrect(color: sliderTheme.inactiveTrackColor)
+           ..rect(color: sliderTheme.activeTrackColor)
+           ..rrect(color: sliderTheme.inactiveTrackColor)
+      ),
+    );
+
+    // Don't stop holding the value indicator.
+    await gesture.up();
+    await tester.pumpAndSettle();
+  });
+
   testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async {
     RangeValues values = const RangeValues(0.3, 0.7);
 
diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart
index 699f554..5445347 100644
--- a/packages/flutter/test/material/slider_test.dart
+++ b/packages/flutter/test/material/slider_test.dart
@@ -1949,6 +1949,96 @@
     await gesture.up();
   });
 
+  testWidgets('Slider removes value indicator from overlay if Slider gets disposed without value indicator animation completing.', (WidgetTester tester) async {
+    final Key sliderKey = UniqueKey();
+    double value = 0.0;
+
+    Widget buildApp({
+      Color activeColor,
+      Color inactiveColor,
+      int divisions,
+      bool enabled = true,
+    }) {
+      return MaterialApp(
+        home: Directionality(
+          textDirection: TextDirection.ltr,
+          child: Material(
+            child: Navigator(onGenerateRoute: (RouteSettings settings) {
+              return MaterialPageRoute<void>(builder: (BuildContext context) {
+                return Column(
+                  children: <Widget>[
+                    Slider(
+                      key: sliderKey,
+                      min: 0.0,
+                      max: 100.0,
+                      divisions: divisions,
+                      label: '${value.round()}',
+                      value: value,
+                      onChanged: (double newValue) {
+                        value = newValue;
+                      },
+                    ),
+                    RaisedButton(
+                      child: const Text('Next'),
+                      onPressed: () {
+                        Navigator.of(context).pushReplacement(
+                          MaterialPageRoute<void>(
+                            builder: (BuildContext context) {
+                              return RaisedButton(
+                                child: const Text('Inner page'),
+                                onPressed: () => Navigator.of(context).pop(),
+                              );
+                            },
+                          ),
+                        );
+                      },
+                    ),
+                  ],
+                );
+              });
+            }),
+          ),
+        ),
+      );
+    }
+
+    await tester.pumpWidget(buildApp(divisions: 3));
+
+    /// The value indicator is added to the overlay when it is clicked or dragged.
+    /// Because both of these gestures are occurring then it adds same value indicator
+    /// twice into the overlay.
+    final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay));
+    final Offset topRight = tester.getTopRight(find.byType(Slider)).translate(-24, 0);
+    final TestGesture gesture = await tester.startGesture(topRight);
+    // Wait for value indicator animation to finish.
+    await tester.pumpAndSettle();
+
+    expect(find.byType(Slider), isNotNull);
+    expect(
+      valueIndicatorBox,
+      paints
+        ..rrect(color: const Color(0xff2196f3)) // Active track.
+        ..rrect(color: const Color(0x3d2196f3)), // Inactive track.
+    );
+
+    await tester.tap(find.text('Next'));
+    await tester.pumpAndSettle();
+
+    expect(find.byType(Slider), findsNothing);
+    expect(
+      valueIndicatorBox,
+      isNot(
+          paints
+            ..rrect(color: const Color(0xff2196f3)) // Active track.
+            ..rrect(color: const Color(0x3d2196f3)) // Inactive track.
+      ),
+    );
+
+    // Don't stop holding the value indicator.
+    await gesture.up();
+    await tester.pumpAndSettle();
+  });
+
   testWidgets('Slider.adaptive', (WidgetTester tester) async {
     double value = 0.5;