Flutter - Using RangeSlider Widget Examples

Range slider is a component that allows the users to select a value range. It's suitable if you have an input where the value is a range. With this component, the users set the minimum and maximum values by performing slides.

A range slider consists of several parts. It has two thumbs, each representing the minimum value and maximum value. Those thumbs can be dragged over a track. The track segment between the two thumbs is called active segment, while the rest are called inactive segments. It can also have value indicators which describe the value of each thumb. In addition, the track can be either continuous or discrete.

In Flutter, you can create such a component by using a widget called RangeSlider. It provides plenty of customizations which enable you to change the behavior or appearance of the slider. Read this tutorial to see the examples.

Using RangeSlider

The constructor of RangeSlider can be seen below.

  RangeSlider({
    Key? key,
    required RangeValues values,
    required ValueChanged<RangeValues>? onChanged,
    ValueChanged<RangeValues>? onChangeStart,
    ValueChanged<RangeValues>? onChangeEnd,
    double min = 0.0,
    double max = 1.0,
    int? divisions,
    RangeLabels? labels,
    Color? activeColor,
    Color? inactiveColor,
    MaterialStateProperty<Color?>? overlayColor,
    MaterialStateProperty<MouseCursor?>? mouseCursor,
    SemanticFormatterCallback? semanticFormatterCallback,
  })

Basic Usage

For the basic usage, you only need to pass two arguments, values and onChanged. The values argument is used to determine the currently selected values (the range). You need to pass a RangeValues instance. The RangeValues class has a constructor with two positional arguments whose type is double, representing the start and end values.

  const RangeValues(double start, double end);

Usually, you need to store it as a state variable, so it can be updated later when the user drags the thumbs. The default minimum and maximum values are 0.0. and 1.0 respectively, so the initial value must be within the allowed range.

  RangeValues _rangeValues = const RangeValues(0.45, 0.55);

The other required argument is onChanged. It's used to handle the events when the selected range changes. It accepts a void function with one parameter of type RangeValues, which is the currently selected values. If the value for values argument is stored in a state variable, you need to update it inside the function. Setting the onChanged argument to null disables the slider.

  RangeSlider(
    values: _rangeValues,
    onChanged: (RangeValues values) {
      setState(() {
        _rangeValues = values;
      });
    },
  )

Output:

Flutter - RangeSlider

You need to be careful when updating the state variable since updating it may cause Flutter to also rebuild other widgets that have nothing to do with the slider value. As a solution, you can put the slider in a separate class or use a StatefulBuilder.

Handle Drag Start and End

To handle when the user starts dragging a thumb, you can pass a void function as the onChangeStart argument. The function also has a parameter of type RangeValues. The similar argument for handling drag end events is onChangeEnd. Although you can handle events using those two arguments, updating the state variable must be done inside the function passed the onChanged argument. If you update it inside the onChangeEnd's function for example, the position of the thumb will only be moved after the drag ends.

  RangeSlider(
    onChangeStart: (RangeValues values) {
      print('onChangeStart');
    },
    onChangeEnd: (RangeValues values) {
      print('onChangedEnd');
    },
    // other arguments
  )

Set Minimum and Maximum Values

The minimum values and maximum values can be changed by passing the min and max arguments respectively. Just make sure the initial range is within the minimum and maximum values.

  RangeSlider(
    min: 0,
    max: 100,
    // other arguments
  )

Set Custom Steps

By default, each thumb can be slid to any position in the track. However, it's also possible to make the slider has discrete steps. Therefore, the thumbs can only be moved to certain positions. It can be done by passing an integer as the divisions argument. If the argument is passed, Flutter will automatically divide the track into several segments according to the argument value. There will be visible tick marks on each position where the thumbs can be dragged to. If the initial start or end value is not exactly on one of the tick marks, it will be moved to the nearest one.

  RangeSlider(
    divisions: 10,
    // other arguments
  )

Output:

Flutter - RangeSlider - Custom Steps Divisions

Set Labels

You can add labels for the start and end thumbs when one of the thumbs is being dragged. To add the labels, pass a RangeLabels value as the labels argument. The RangeLabels itself can be created using the constructor below.

    const RangeLabels(String start, String end)

Usually, the displayed label is the current value of the respective thumb.

  RangeSlider(
    labels: RangeLabels(_rangeValues.start.toString(), _rangeValues.end.toString()),
    // other arguments
  )

Output:

Flutter - RangeSlider - Labels

Set Track and Thumb Colors

Flutter also provides some arguments to customize the colors. The color of the active segment can be set by passing a Color as the activeColor argument. It defaults to ColorScheme.primary. The activeColor value also affects the color of the thumb. Meanwhile, the argument to set the color of the inactive segments is inactiveColor. It defaults to ColorScheme.primary with an opacity of 0.24.

When a thumb is being dragged, the highlight color surrounding the thumb can be set by passing a MaterialStateProperty as the overlayColor argument. If this argument is null, the default value is activeColor with an opacity of 0.12. If the activeColor is also null, then it will use ColorScheme.primary with an opacity of 0.12.

  RangeSlider(
    activeColor: Colors.purpleAccent,
    inactiveColor: Colors.grey,
    overlayColor: MaterialStateProperty.all(Colors.red),
    // other arguments
  )

Output:

Flutter - RangeSlider - Colors

Set SliderThemeData

There are a lot more customizations that you can apply if you use SliderThemeData. However, despite providing more customizations, the styles set by SliderThemeData can be overridden by the corresponding arguments passed to the constructor of SliderRange.

  SliderThemeData({
    double? trackHeight,
    Color? activeTrackColor,
    Color? inactiveTrackColor,
    Color? secondaryActiveTrackColor,
    Color? disabledActiveTrackColor,
    Color? disabledInactiveTrackColor,
    Color? disabledSecondaryActiveTrackColor,
    Color? activeTickMarkColor,
    Color? inactiveTickMarkColor,
    Color? disabledActiveTickMarkColor,
    Color? disabledInactiveTickMarkColor,
    Color? thumbColor,
    Color? overlappingShapeStrokeColor,
    Color? disabledThumbColor,
    Color? overlayColor,
    Color? valueIndicatorColor,
    SliderComponentShape? overlayShape,
    SliderTickMarkShape? tickMarkShape,
    SliderComponentShape? thumbShape,
    SliderTrackShape? trackShape,
    SliderComponentShape? valueIndicatorShape,
    RangeSliderTickMarkShape? rangeTickMarkShape,
    RangeSliderThumbShape? rangeThumbShape,
    RangeSliderTrackShape? rangeTrackShape,
    RangeSliderValueIndicatorShape? rangeValueIndicatorShape,
    ShowValueIndicator? showValueIndicator,
    TextStyle? valueIndicatorTextStyle,
    double? minThumbSeparation,
    RangeThumbSelector? thumbSelector,
    MaterialStateProperty<MouseCursor?>? mouseCursor,
  })

As you can see from the constructor above, there are plenty of arguments that you can use to modify a RangeSlider. However, since SliderThemeData is also used for the Slider widget, there are some arguments that don't have any effect on RangeSlider.

There are two ways to use SliderThemeData. First, you can wrap the RangeSlider as the child of a SliderTheme. Besides the child argument, the SliderTheme's constructor requires you to pass an argument named data whose type is SliderThemeData. It affects all RangeSlider widgets under the tree of the SliderTheme.

  const SliderTheme({
    Key? key,
    required SliderThemeData data,
    required Widget child,
  })

The below examples creates a new SliderThemeData.

  SliderTheme(
    data: SliderThemeData(
      // arguments
    ),
    child: RangeSlider(
      // arguments
    ),
  )

It's also possible to copy the existing SliderThemeData from the BuildContext using the copyWith method.

  SliderTheme(
    data: SliderTheme.of(context).copyWith(
      // arguments
    ),
    child: RangeSlider(
      // arguments
    ),
  )

Another way is by setting it as the slider theme that affects all SliderRange widgets in the application. You can do it by passing it as the sliderTheme of a ThemeData. The ThemeData itself has to be set as the theme of the MaterialApp.The styles set using this method can be overridden by the theme data of a SliderTheme widget.

  MaterialApp(
    title: 'Woolha.com Flutter Tutorial',
    theme: ThemeData.light().copyWith(
      sliderTheme: SliderThemeData(
    ),
  )

Below I'm going to show you some of the customizations that can be applied using SliderThemeData .

Set Track Height

The height of the track can be set using the trackHeight argument.

  SliderThemeData(
    trackHeight: 8,
    // other arguments
  )

Output:

Flutter - Range Slider - Theme - Track Height

Set Track Colors

With SliderThemeData, it's possible to set the colors for active and inactive segments by passing a Color as the activeTrackColor and inactiveTrackColor arguments respectively. In addition, you can also set different colors for the track when the slider is disabled using disabledActiveTrackColor and disabledInactiveTrackColor arguments.

  SliderThemeData(
    activeTrackColor: Colors.pinkAccent,
    inactiveTrackColor: Colors.yellow,
    disabledActiveTrackColor: Colors.grey,
    disabledInactiveTrackColor: Colors.grey.withOpacity(0.5),
    // other arguments
  )

Output:

Flutter - RangeSlider - Theme - Track Colors

Set Tick Mack Colors

The tick mark colors can be customized as well. Those in the active segment can by passing a Color as the activeTickMarkColor argument. For the tick marks in inactive segments, you can set a Color value as the inactiveTickMarkColor argument. The arguments to be used when the slider is disabled are disabledActiveTickMarkColor and disabledInactiveTickMarkColor

  SliderThemeData(
    activeTickMarkColor: Colors.white,
    inactiveTickMarkColor: Colors.white60,
    disabledActiveTickMarkColor: Colors.black26,
    disabledInactiveTickMarkColor: Colors.black12,
    // other arguments
  )

Output:

Flutter - RangeSlider - Theme - Tick Mark Colors

Set Tick Mark Shape

The shape of the tick marks can be changed by passing a RangeSliderTickMarkShape instance as the rangeTickMarkShape argument. The default value is RoundRangeSliderTickMarkShape whose radius is 1/4 of the track height. The example below also uses RoundRangeSliderTickMarkShape but with a different radius. If you want to use a different shape, you need to create a custom class that extends RangeSliderTickMarkShape.

  SliderThemeData(
    rangeTickMarkShape: RoundRangeSliderTickMarkShape(
      tickMarkRadius: 5,
    ),
    // other arguments
  )

Output:

Flutter - RangeSlider - Theme - Tick Mark Shape

Set Thumb Color

You can pass a Color value as the thumbColor argument to set the color of the thumbs.

  SliderThemeData(
    thumbColor: Colors.teal,
    // other arguments
  )

Output:

Flutter - RangeSlider - Theme - Thumb Color

Set Thumb Shape

To change the thumb shape, you have to pass the rangeTickMarkShape argument whose type is RangeSliderTickMarkShape. It defaults to RoundSliderTickMarkShape. The example below uses RoundRangeSliderTickMarkShape with a custom radius. To use another shape other than rounded, create your own class that extends RangeSliderTickMarkShape.

  SliderThemeData(
    rangeThumbShape: RoundRangeSliderThumbShape(
      enabledThumbRadius: 15,
    ),
    // other arguments
  )

Output:

Flutter - RangeSlider - Theme - Thumb Shape

RangeSlider Parameters

  • Key? key: The widget's key, used to control how a widget is replaced with another.
  • required RangeValues values: The currently selected values.
  • required ValueChanged<RangeValues>? onChanged: Function to be called when the user is dragging the thumb to change the values.
  • ValueChanged<RangeValues>? onChangeStart: Function to be called when the user starts selecting a new range.
  • ValueChanged<RangeValues>? onChangeEnd: Function to be called when the user has done selecting a new range.
  • double min: The minimum value. Defaults to 0.0.
  • double max: The maximum value. Defaults to 1.0.
  • RangeLabels? labels: Labels to be displayed.
  • Color? activeColor: The color of the thumb and the track's active segment.
  • Color? inactiveColor: The color of the track's inactive segments.
  • MaterialStateProperty<Color?>? overlayColor: The highlight color which indicates that the thumb is hovered or dragged.
  • MaterialStateProperty<MouseCursor?>? mouseCursor: The mouse cursor when the pointer enters or is hovering over the widget.
  • SemanticFormatterCallback? semanticFormatterCallback: The callback used to create a semantic value from the slider's values..

SliderThemeData Parameters

  • double? trackHeight: The height of the track.
  • Color? activeTrackColor: The color of the track's active segment.
  • Color? inactiveTrackColor: The color of the track's inactive segments.
  • Color? secondaryActiveTrackColor: Doesn't have any effect on SliderRange.
  • Color? disabledActiveTrackColor: The color of the track's active segment when disabled.
  • Color? disabledInactiveTrackColor: The color of the track's inactive segment when disabled.
  • Color? disabledSecondaryActiveTrackColor: Doesn't have any effect on SliderRange.
  • Color? activeTickMarkColor: The color of tick marks in active segment.
  • Color? inactiveTickMarkColor: The color of tick marks in inactive segments.
  • Color? disabledActiveTickMarkColor: The color of tick marks in active segment when disabled.
  • Color? disabledInactiveTickMarkColor: The color of tick marks in inactive segment when disabled.
  • Color? thumbColor: Color of the thumbs.
  • Color? overlappingShapeStrokeColor: The color given to the top thumb's perimeter when the thumbs are overlapping.
  • Color? disabledThumbColor: Color of the thumbs when disabled.
  • Color? overlayColor: The color of the overlay around the thumb when pressed, focused, or hovered.
  • Color? valueIndicatorColor: The color for the value indicator.
  • SliderComponentShape? overlayShape: The shape for the thumbs' overlay.
  • SliderTickMarkShape? tickMarkShape: Doesn't have any effect on SliderRange.
  • SliderComponentShape? thumbShape: Doesn't have any effect on SliderRange.
  • SliderTrackShape? trackShape: Doesn't have any effect on SliderRange.
  • SliderComponentShape? valueIndicatorShape: Doesn't have any effect on SliderRange.
  • RangeSliderTickMarkShape? rangeTickMarkShape: The shape of the tick marks.
  • RangeSliderThumbShape? rangeThumbShape: The shape of the thumbs.
  • RangeSliderTrackShape? rangeTrackShape: The shape of the track.
  • RangeSliderValueIndicatorShape? rangeValueIndicatorShape: The shape of the value indicators.
  • ShowValueIndicator? showValueIndicator: Whether the value indicator should be shown.
  • TextStyle? valueIndicatorTextStyle: The text style of the value indicators.
  • double? minThumbSeparation: The minimum distance between the thumbs.
  • RangeThumbSelector? thumbSelector: A function that determines which thumb to be selected when the slider is interacted with.
  • MaterialStateProperty<MouseCursor?>? mouseCursor: The mouse cursor when the pointer enters or is hovering over the widget.

Full Code

  import 'package:flutter/material.dart';
  
  void main() => runApp(const MyApp());
  
  class MyApp extends StatelessWidget {
  
    const MyApp({Key? key}) : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        theme: ThemeData.light().copyWith(
          sliderTheme: const SliderThemeData(
            // thumbColor: Colors.yellow,
          )
        ),
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Woolha.com Flutter Tutorial'),
            backgroundColor: Colors.teal,
          ),
          body: const RangeSliderExample(),
        ),
      );
    }
  }
  
  class RangeSliderExample extends StatefulWidget {
  
    const RangeSliderExample({super.key});
  
    @override
    State<StatefulWidget> createState() {
      return _RangeSliderExampleState();
    }
  }
  
  class _RangeSliderExampleState extends State<RangeSliderExample> {
  
    RangeValues _rangeValues = const RangeValues(40, 60);
  
    @override
    Widget build(BuildContext context) {
      return Padding(
        padding: const EdgeInsets.symmetric(horizontal: 10),
        child: Center(
            child: SliderTheme(
              // data: SliderTheme.of(context).copyWith(
              data: SliderThemeData(
                trackHeight: 8,
                activeTrackColor: Colors.pinkAccent,
                inactiveTrackColor: Colors.yellow,
                disabledActiveTrackColor: Colors.grey,
                disabledInactiveTrackColor: Colors.grey.withOpacity(0.5),
                activeTickMarkColor: Colors.white,
                inactiveTickMarkColor: Colors.white60,
                disabledActiveTickMarkColor: Colors.black26,
                disabledInactiveTickMarkColor: Colors.black12,
                rangeTickMarkShape: const RoundRangeSliderTickMarkShape(
                  tickMarkRadius: 5,
                ),
                thumbColor: Colors.teal,
                rangeThumbShape: const RoundRangeSliderThumbShape(
                  enabledThumbRadius: 15,
                ),
              ),
              child: Container(
                child: RangeSlider(
                  min: 0,
                  max: 100,
                  divisions: 10,
                  labels: RangeLabels(_rangeValues.start.toString(), _rangeValues.end.toString()),
                  // activeColor: Colors.purpleAccent,
                  // inactiveColor: Colors.grey,
                  overlayColor: MaterialStateProperty.all(Colors.red),
                  values: _rangeValues,
                  onChangeStart: (RangeValues values) {
                    print('onChangeStart');
                  },
                  onChangeEnd: (RangeValues values) {
                    print('onChangedEnd');
                  },
                  onChanged: (RangeValues values) {
                    print('onChanged');
                    setState(() {
                      _rangeValues = values;
                    });
                  },
                ),
              ),
            )
        ),
      );
    }
  }

Summary

In this tutorial, we have learned how to create a range slider in Flutter using the RangeSlider widget. It allows you to set the minimum and maximum values and set custom steps by dividing the track into several segments. The widget also allows you to customize the appearance by defining a SliderThemeData.

You can also read about: