Flutter slider with gradient

3,013

Solution 1

I've now created a custom track shape class based on this youtube video and added a gradient property into the constructor.

How to use it:

Gradient:

LinearGradient gradient = LinearGradient(
 colors: <Color> [
  Colors.red,
  Colors.orange,
  Colors.yellow,
  Colors.green,
  Colors.blue,
  Colors.blue[900],
  Colors.purple
 ]
);

Slider:
(The property darkenInactive = false is used to not darken the slider on the inactive side.)

SliderTheme(
 data: SliderThemeData(
  trackShape: GradientRectSliderTrackShape(gradient: gradient, darkenInactive: false),
 ),
 child: Slider(
  min: 0,
  max: 10,
  value: value,
  onChanged: (double value) {},
  )
),

Shape class:

import 'package:flutter/material.dart';

/// Based on https://www.youtube.com/watch?v=Wl4F5V6BoJw

class GradientRectSliderTrackShape extends SliderTrackShape
    with BaseSliderTrackShape {
  const GradientRectSliderTrackShape({
    this.gradient = const LinearGradient(
      colors: [
        Colors.red,
        Colors.yellow,
      ],
    ),
    this.darkenInactive = true,
  });

  final LinearGradient gradient;
  final bool darkenInactive;

  @override
  void paint(
      PaintingContext context,
      Offset offset,
      {
        required RenderBox parentBox,
        required SliderThemeData sliderTheme,
        required Animation<double> enableAnimation,
        required TextDirection textDirection,
        required Offset thumbCenter,
        bool isDiscrete = false,
        bool isEnabled = false,
        double additionalActiveTrackHeight = 2,
      }
    ) {
    assert(sliderTheme.disabledActiveTrackColor != null);
    assert(sliderTheme.disabledInactiveTrackColor != null);
    assert(sliderTheme.activeTrackColor != null);
    assert(sliderTheme.inactiveTrackColor != null);
    assert(sliderTheme.thumbShape != null);
    assert(sliderTheme.trackHeight != null && sliderTheme.trackHeight! > 0);

    final Rect trackRect = getPreferredRect(
      parentBox: parentBox,
      offset: offset,
      sliderTheme: sliderTheme,
      isEnabled: isEnabled,
      isDiscrete: isDiscrete,
    );

    final activeGradientRect = Rect.fromLTRB(
      trackRect.left,
      (textDirection == TextDirection.ltr)
          ? trackRect.top - (additionalActiveTrackHeight / 2)
          : trackRect.top,
      thumbCenter.dx,
      (textDirection == TextDirection.ltr)
          ? trackRect.bottom + (additionalActiveTrackHeight / 2)
          : trackRect.bottom,
    );

    // Assign the track segment paints, which are leading: active and
    // trailing: inactive.
    final ColorTween activeTrackColorTween = ColorTween(
        begin: sliderTheme.disabledActiveTrackColor,
        end: sliderTheme.activeTrackColor);
    final ColorTween inactiveTrackColorTween = darkenInactive
        ? ColorTween(
          begin: sliderTheme.disabledInactiveTrackColor,
          end: sliderTheme.inactiveTrackColor
        )
        : activeTrackColorTween;
    final Paint activePaint = Paint()
      ..shader = gradient.createShader(activeGradientRect)
      ..color = activeTrackColorTween.evaluate(enableAnimation)!;
    final Paint inactivePaint = Paint()
      ..color = inactiveTrackColorTween.evaluate(enableAnimation)!;
    final Paint leftTrackPaint;
    final Paint rightTrackPaint;
    switch (textDirection) {
      case TextDirection.ltr:
        leftTrackPaint = activePaint;
        rightTrackPaint = inactivePaint;
        break;
      case TextDirection.rtl:
        leftTrackPaint = inactivePaint;
        rightTrackPaint = activePaint;
        break;
    }

    final Radius trackRadius = Radius.circular(trackRect.height / 2);
    final Radius activeTrackRadius = Radius.circular(trackRect.height / 2 + 1);

    context.canvas.drawRRect(
      RRect.fromLTRBAndCorners(
        trackRect.left,
        (textDirection == TextDirection.ltr)
            ? trackRect.top - (additionalActiveTrackHeight / 2)
            : trackRect.top,
        thumbCenter.dx,
        (textDirection == TextDirection.ltr)
            ? trackRect.bottom + (additionalActiveTrackHeight / 2)
            : trackRect.bottom,
        topLeft: (textDirection == TextDirection.ltr)
            ? activeTrackRadius
            : trackRadius,
        bottomLeft: (textDirection == TextDirection.ltr)
            ? activeTrackRadius
            : trackRadius,
      ),
      leftTrackPaint,
    );
    context.canvas.drawRRect(
      RRect.fromLTRBAndCorners(
        thumbCenter.dx,
        (textDirection == TextDirection.rtl)
            ? trackRect.top - (additionalActiveTrackHeight / 2)
            : trackRect.top,
        trackRect.right,
        (textDirection == TextDirection.rtl)
            ? trackRect.bottom + (additionalActiveTrackHeight / 2)
            : trackRect.bottom,
        topRight: (textDirection == TextDirection.rtl)
            ? activeTrackRadius
            : trackRadius,
        bottomRight: (textDirection == TextDirection.rtl)
            ? activeTrackRadius
            : trackRadius,
      ),
      rightTrackPaint,
    );
  }
}

enter image description here

(Github Gist)

Solution 2

Use this library. It's really easy to implement with it,

https://pub.dev/packages/flutter_xlider

        FlutterSlider(
          values: [40],
          max: 100,
          min: 0,
          trackBar: FlutterSliderTrackBar(
            activeTrackBar: BoxDecoration(
              gradient: AppColors.sliderGradient,
              borderRadius: BorderRadius.circular(5)
            ),
            activeTrackBarHeight: 6,
          ),
          onDragging: (handlerIndex, lowerValue, upperValue) {
            
          },
        );

**Update
Seems like the pub version hasn't been updated to null safety. But the master branch has it. Use as below for null safety version

flutter_xlider:
  git:
    url: https://github.com/Ali-Azmoud/flutter_xlider.git
    ref: master

Solution 3

You can try this;

Widget get gradientContainer => Container(
    width: double.infinity,
    height: height,
    decoration: BoxDecoration(
        gradient: gradient
    ),
  );

Widget get slider =>SliderTheme(
  data: SliderThemeData(
      trackShape: CustomTrackShape(),
      activeTrackColor: Colors.transparent,
      inactiveTrackColor: Colors.red,
      thumbColor: Colors.white,
      overlayColor: Colors.transparent
  ),
  child: Slider(
      value: value,
      max: max,
      min: min,
      onChanged: (double newValue){
        setState(() {
          value=newValue;
        });
      }
  )

);

And for throw the track padding on slider, our custom track shape class is here too;

class CustomTrackShape extends RoundedRectSliderTrackShape {
  Rect getPreferredRect({
    @required RenderBox parentBox,
    Offset offset = Offset.zero,
    @required SliderThemeData sliderTheme,
    bool isEnabled = false,
    bool isDiscrete = false,
  }) {
    final double trackHeight = sliderTheme.trackHeight;
    final double trackLeft = offset.dx;
    final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
    final double trackWidth = parentBox.size.width;
    return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
  }
}

and we can finally merge them;

  Widget get gradientSlider=>Padding(
  child: SizedBox(
    child: Stack(
      children: [
        gradientContainer,
        slider,
      ],
      alignment: Alignment.center,
    ),
  ),
  padding: padding

);

and lastly you just must the fill padding, width, height, gradient button container height properties, just it.

result; enter image description here

Share:
3,013
CinePlays
Author by

CinePlays

Updated on December 24, 2022

Comments

  • CinePlays
    CinePlays over 1 year

    I was wondering if there is a way of creating a slider widget in Flutter with a gradient color. Here is a link to the slider class, but there's no "SliderTheme" or something like that.

    • pskink
      pskink over 3 years
      what do you mean by 'but there's no "SliderTheme"'?
    • CinePlays
      CinePlays over 3 years
      e.g in a text widget you can add a style (TextTheme) to change the size, color and font.
    • pskink
      pskink over 3 years
      api.flutter.dev/flutter/material/SliderTheme-class.html - and if you dont have a local API docs installed you can always check api.flutter.dev/index.html - they have nice Search API Docs search field in the top right corner
    • CinePlays
      CinePlays over 3 years
      but how can I add a gradient? There're only Color properties and no paint (text widget) or gradient property.
    • pskink
      pskink over 3 years
      check *Shape properties
  • Arslan Kaleem
    Arslan Kaleem almost 3 years
    Almost my problem is solved but I want to show colors till the nobe and inactive part will remain transparent
  • Arsen Tatraev
    Arsen Tatraev over 2 years
    It's good, but it is not Null safety now.
  • Kasun Thilina
    Kasun Thilina over 2 years
    There's a null safety version in the github repo. I have updated the answer with that
  • Suj
    Suj about 2 years
    thanks man for updating answer
  • Suj
    Suj about 2 years
    work like charm Thanks man really appreciate.
  • Hitesh Kumar Saini
    Hitesh Kumar Saini about 2 years
    Epic answer. Take my upvote.