Reputation: 513
I'm having problems to create a custom slider on flutter. The image is the following one:
I know how to create it on XML on Android, but with flutter, I'm having problems. In the Slider class constructor is not a parameter for slider background from assets or a thumb from assets.
Anyone could please help me/ guide me, about how to achieve the expected result? Thanks.
Upvotes: 1
Views: 2438
Reputation: 10463
It's possible to create a custom Slider in Flutter. You can visit this guide to learn more. Then you can use RotatedBox
if you need the Slider to be vertical.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Custom Slider Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: RotatedBox(quarterTurns: 1, child: SliderWidget()),
),
);
}
}
class CustomSliderThumbCircle extends SliderComponentShape {
final double thumbRadius;
final int min;
final int max;
const CustomSliderThumbCircle({
required this.thumbRadius,
this.min = 0,
this.max = 10,
});
@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return Size.fromRadius(thumbRadius);
}
@override
void paint(
PaintingContext context,
Offset center, {
Animation<double>? activationAnimation,
Animation<double>? enableAnimation,
bool? isDiscrete,
TextPainter? labelPainter,
RenderBox? parentBox,
required SliderThemeData sliderTheme,
TextDirection? textDirection,
required double value,
double? textScaleFactor,
Size? sizeWithOverflow,
}) {
final Canvas canvas = context.canvas;
final paint = Paint()
..shader = LinearGradient(
colors: [
const Color(0xFF00c6ff),
const Color(0xFF0072ff),
],
).createShader(Rect.fromCircle(
center: Offset.fromDirection(0.0, 1.0),
radius: 1.0,
));
Paint paintBorder = new Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 3.0;
canvas.drawCircle(center, thumbRadius * .9, paint);
canvas.drawCircle(center, thumbRadius * .9, paintBorder);
}
String getValue(double value) {
return (min + (max - min) * value).round().toString();
}
}
class SliderWidget extends StatefulWidget {
final double sliderHeight;
final int min;
final int max;
final fullWidth;
SliderWidget(
{this.sliderHeight = 48,
this.max = 10,
this.min = 0,
this.fullWidth = false});
@override
_SliderWidgetState createState() => _SliderWidgetState();
}
class _SliderWidgetState extends State<SliderWidget> {
double _value = 0;
@override
Widget build(BuildContext context) {
double paddingFactor = .2;
if (this.widget.fullWidth) paddingFactor = .3;
return Container(
width: this.widget.fullWidth
? double.infinity
: (this.widget.sliderHeight) * 5.5,
height: (this.widget.sliderHeight),
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(
Radius.circular((this.widget.sliderHeight * .3)),
),
gradient: new LinearGradient(
colors: [
const Color(0xFF00c6ff),
const Color(0xFF0072ff),
],
begin: const FractionalOffset(0.0, 0.0),
end: const FractionalOffset(1.0, 1.00),
stops: [0.0, 1.0],
tileMode: TileMode.clamp),
),
child: Padding(
padding: EdgeInsets.fromLTRB(this.widget.sliderHeight * paddingFactor,
2, this.widget.sliderHeight * paddingFactor, 2),
child: Row(
children: <Widget>[
/// Optional Text for min value
// Text(
// '${this.widget.min}',
// textAlign: TextAlign.center,
// style: TextStyle(
// fontSize: this.widget.sliderHeight * .3,
// fontWeight: FontWeight.w700,
// color: Colors.white,
// ),
// ),
SizedBox(
width: this.widget.sliderHeight * .1,
),
Expanded(
child: Center(
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
/// Color of the active track - left of the thumb slider
activeTrackColor: Colors.white.withOpacity(1),
/// Color of the inactive track - right of the thumb slider
inactiveTrackColor: Colors.white.withOpacity(1),
/// Track height
trackHeight: 10.0,
thumbShape: CustomSliderThumbCircle(
thumbRadius: this.widget.sliderHeight * .3,
min: this.widget.min,
max: this.widget.max,
),
overlayColor: Colors.white.withOpacity(.4),
//valueIndicatorColor: Colors.white,
activeTickMarkColor: Colors.white,
inactiveTickMarkColor: Colors.red.withOpacity(.7),
),
child: Slider(
value: _value,
onChanged: (value) {
setState(() {
_value = value;
});
}),
),
),
),
SizedBox(
width: this.widget.sliderHeight * .1,
),
/// Optional Text for max value
// Text(
// '${this.widget.max}',
// textAlign: TextAlign.center,
// style: TextStyle(
// fontSize: this.widget.sliderHeight * .3,
// fontWeight: FontWeight.w700,
// color: Colors.white,
// ),
// ),
],
),
),
);
}
}
Upvotes: 1