Tutorial and code of Slider Number Picker in Flutter. Copy and paste the below code as per your requirements.
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Horizontal Number Picker',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(child: Text("Slider Number Picker"),),
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Container(
child: HorizontalNumberPicker()
),
),
),
);
}
}
class HorizontalNumberPicker extends StatefulWidget {
final double width;
final double height;
const HorizontalNumberPicker({
Key? key,
this.width = 300,
this.height = 100
});
@override
_HorizontalNumberPickerState createState() => _HorizontalNumberPickerState();
}
class _HorizontalNumberPickerState
extends State<HorizontalNumberPicker>
with SingleTickerProviderStateMixin{
double sliderPadding = 50;
double _sliderPercent = 0;
double _sliderPosition = 0;
final int minValue = 0;
final int maxValue = 100;
late Animation<double> _animation;
late AnimationController _animationController;
void _updatePosition(Offset offSet){
double newPosition;
if(offSet.dx <= 0){
newPosition = 0;
}else if(offSet.dx >= widget.width-sliderPadding){
newPosition = widget.width-sliderPadding;
}else{
newPosition = offSet.dx;
}
setState(() {
_sliderPosition = newPosition;
_sliderPercent = newPosition / widget.width-sliderPadding;
});
}
void _horizontalDragStart(BuildContext context, DragStartDetails details) {
RenderBox? box = context.findRenderObject() as RenderBox?;
Offset? offset = box?.globalToLocal( details.globalPosition);
_animationController.forward();
_updatePosition(offset!);
}
void _horizontalDragUpdate(BuildContext context, DragUpdateDetails details) {
RenderBox? box = context.findRenderObject() as RenderBox?;
Offset? offset = box?.globalToLocal( details.globalPosition);
_updatePosition(offset!);
}
void _horizontalDragEnd(DragEndDetails details) {
_animationController.reverse();
setState(() {});
}
@override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 300)
);
_animation = Tween<double>(
begin: 0, end: 15
).animate(
CurvedAnimation(
parent: _animationController,
curve: Curves.linear
)
);
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
width: widget.width,
height: widget.height,
child: GestureDetector(
onHorizontalDragStart: (d)=> _horizontalDragStart(context, d),
onHorizontalDragUpdate: (d) => _horizontalDragUpdate(context, d),
onHorizontalDragEnd: _horizontalDragEnd,
child: AnimatedBuilder(
animation: _animationController,
builder: (c, ch){
return Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
left: 0,
bottom: widget.height/5.5,
child: Text("$minValue")),
Positioned(
right: 0,
bottom: widget.height/5.5,
child: Text("$maxValue")),
Container(
width: widget.width-sliderPadding,
height: widget.height-sliderPadding,
child: CustomPaint(
painter: LinePainter(
minValue: minValue,
maxValue: maxValue,
indicatorMargin: _animation.value,
dragPercent: _sliderPercent,
sliderPosition: _sliderPosition
),
),
),
],
);
},
),
),
);
}
}
class LinePainter extends CustomPainter{
double sliderPosition;
final double dragPercent;
final Paint linePainter;
final Paint indicatorPainter;
final TextPainter minValuePainter;
final TextPainter maxValuePainter;
final TextPainter selectedValuePainter;
final int minValue;
final int maxValue;
static int _selectedValue = 0;
final double indicatorMargin;
LinePainter({
required this.maxValue,
required this.minValue,
required this.indicatorMargin,
required this.sliderPosition,
required this.dragPercent
}):
selectedValuePainter = TextPainter(
textAlign: TextAlign.center,
text: TextSpan(
text: "$_selectedValue",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 25.45+indicatorMargin,
)
)
)
..textDirection = TextDirection.ltr,
maxValuePainter = TextPainter(
textAlign: TextAlign.center,
text: TextSpan(
text: "$maxValue",
style: TextStyle(
color: Colors.grey,
fontSize: 18,
)
)
)
..textDirection = TextDirection.ltr,
minValuePainter = TextPainter(
textAlign: TextAlign.center,
text: TextSpan(
text: "$minValue",
style: TextStyle(
color: Colors.grey,
fontSize: 18,
)
)
)
..textDirection = TextDirection.ltr,
indicatorPainter = Paint()
..color = Colors.black
..style = PaintingStyle.fill,
linePainter = Paint()
..color = Colors.grey
..style = PaintingStyle.stroke
..strokeWidth = 1.9;
@override
void paint(Canvas canvas, Size size) {
canvas.translate(0, size.height/2);
_selectedValue = (sliderPosition / size.width * 100).toInt();
double controlHeight = indicatorMargin;
double bezierWidth = 40.0;
double bendWidth = 40.0;
double indicatorRadius = 8.5;
double centerPoint = sliderPosition;
centerPoint = centerPoint > size.width ? size.width : centerPoint;
double startBend = sliderPosition - bendWidth/2;
double startOfBezier = startBend - bezierWidth;
double endBend = sliderPosition + bendWidth/2;
double endOfBezier = endBend + bezierWidth;
double lcp1 = startBend;
double lcp2 = startBend;
double rcp1 = endBend;
double rcp2 = endBend;
startBend = (startBend <= 0.0) ? 0.0 : startBend;
startOfBezier = (startOfBezier <= 0.0) ? 0.0 : startOfBezier;
endBend = (endBend >= size.width) ? size.width : endBend;
endOfBezier = (endOfBezier >= size.width) ? size.width : endOfBezier;
Path p = Path();
p.moveTo(-25, 0);
p.lineTo(startOfBezier, 0);
p.cubicTo(lcp1, 0, lcp2, -controlHeight, centerPoint, -controlHeight);
p.cubicTo(rcp1, -controlHeight, rcp2, 0, endOfBezier, 0);
p.lineTo(size.width+25, 0);
canvas.drawPath(p, linePainter);
canvas.drawCircle(
Offset(sliderPosition, 24.5-indicatorMargin), indicatorRadius,
indicatorPainter
);
/*
minValuePainter.layout();
minValuePainter.paint(canvas, Offset(marginStart, 16));
maxValuePainter.layout();
maxValuePainter.paint(canvas, Offset(marginEnd, 16));
*/
selectedValuePainter.layout();
selectedValuePainter.paint(
canvas,
Offset((sliderPosition-indicatorRadius), -42-indicatorMargin-controlHeight)
);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}