How to draw custom thumb in Flutter Slider?
In Flutter Slider, you can easily customize the sliders’ thumb to achieve various scenarios. This article will assist you in creating a volume bar, as shown in the following image.

Step 1: Add the Syncfusion® Flutter Sliders package to your dependencies in the pubspec.yaml file.
Step 2: Initialize the SfSlider widget as a child of any widget. Now, set the values for the SfSlider.min and SfSlider.max properties. The value of the SfSlider.value property should be between the min and max values. Set the _CustomThumbShape() to the SfSlider.thumbShape property.
double _value = 50.0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
children: [
SizedBox(
width: 30,
child: Center(
child: Text(
'${_value.toInt()}',
style: TextStyle(color: _value > 90 ? Colors.red : Colors.black),
)),
),
Expanded(
child: SfSliderTheme(
data: SfSliderThemeData(
trackCornerRadius: 7.5,
activeTrackHeight: 15,
inactiveTrackHeight: 15,
overlayRadius: 0.0),
child: SfSlider(
min: 0.0,
max: 100.0,
value: _value,
thumbShape: _CustomThumbShape(),
onChanged: (dynamic value) {
setState(() {
_value = value;
});
},
),
),
),
],
),
),
);
}
Step 3: Extend the SfThumbShape class to create a custom shape. Override the paint method and draw a shape that you want. You can obtain the current value, thumb pixel value, text direction, and theme data values as a paint methods’ parameters. Using these values, created a volume slider.
class _CustomThumbShape extends SfThumbShape {
// Converts degree to radians.
double degreeToRadians(num deg) => deg * (pi / 180.0);
@override
void paint(PaintingContext context, Offset center,
{required RenderBox parentBox,
required RenderBox? child,
required SfSliderThemeData themeData,
SfRangeValues? currentValues,
dynamic currentValue,
required Paint? paint,
required Animation<double> enableAnimation,
required TextDirection textDirection,
required SfThumb? thumb}) {
final Path path = Path();
final Paint paint = Paint()
..color = currentValue > 90 ? Colors.red : Colors.black
..style = PaintingStyle.fill
..strokeWidth = 2;
path.moveTo(center.dx, center.dy - 10);
path.lineTo(center.dx, center.dy + 10);
path.lineTo(center.dx - 5, center.dy + 3);
path.lineTo(center.dx - 10, center.dy + 3);
path.lineTo(center.dx - 10, center.dy - 3);
path.lineTo(center.dx - 5, center.dy - 3);
path.close();
context.canvas.drawPath(path, paint);
paint
..style = PaintingStyle.stroke
..strokeWidth = 2;
path.reset();
if (currentValue == 0) {
paint.color = Colors.red;
path.moveTo(center.dx + 3, center.dy - 8);
path.lineTo(center.dx - 8, center.dy + 8);
} else {
for (int i = 1; i <= 3; i++) {
path.moveTo(center.dx + (i * 2), center.dy);
path.arcTo(
Rect.fromCenter(
center: Offset(center.dx + (i * 2), center.dy),
width: i * 3,
height: i * 6),
degreeToRadians(270),
degreeToRadians(180),
true);
if (i * 33 > currentValue) {
break;
}
}
}
context.canvas.drawPath(path, paint);
}
}
Output

Check the following links for more features in Syncfusion® Flutter Sliders:
Live samples