我正在尝试自定义滑块小部件以具有自定义的拇指形状。为此,我必须扩展SliderComponentShape
。此类要求我实现自己的绘画方法。绘制方法仅给我一个Canvas
可供绘制。不幸的是,我要使用的拇指形状相当复杂。手动绘制它会很繁琐,而使用flutters进行构建则要容易得多。有没有办法将Widget
绘制为Canvas
?
您可以使用可绘制的图像或矢量作为拇指图像,并降低绘制的复杂度。
例如,如下所示获取地图滑块
您可以使用以下代码,并将图像文件用作拇指图标
class DistanceSlider extends StatefulWidget {
const DistanceSlider({
Key key,
@required this.imageUrl,
@required this.minDistance,
@required this.maxDistance,
}) : super(key: key);
final String imageUrl;
final double maxDistance;
final double minDistance;
@override
_DistanceSliderState createState() => _DistanceSliderState();
}
class _DistanceSliderState extends State<DistanceSlider> {
double distance = 20;
ui.Image customImage;
Future<ui.Image> loadImage(String imageUrl) async {
ByteData data = await rootBundle.load(imageUrl);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
ui.FrameInfo fi = await codec.getNextFrame();
return fi.image;
}
@override
void initState() {
loadImage(widget.imageUrl).then((image) {
setState(() {
customImage = image;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
child: SliderTheme(
data: SliderThemeData(
trackHeight: 8,
thumbShape: SliderThumbImage(
image: customImage,
thumbRadius: 0,
max: widget.maxDistance.toInt()),
overlayColor: kSecondaryColorLight.withAlpha(32),
overlayShape: RoundSliderOverlayShape(overlayRadius: 28.0),
activeTrackColor: kSecondaryColorDark,
inactiveTrackColor: kSecondaryColorLight.withOpacity(0.5),
valueIndicatorShape: PaddleSliderValueIndicatorShape(),
valueIndicatorTextStyle: TextStyle(
color: Colors.white,
),
valueIndicatorColor: Colors.white,
),
child: Stack(
children: <Widget>[
Slider(
label: distance.abs().toString(),
value: distance,
min: widget.minDistance,
max: widget.maxDistance,
onChanged: (value) {
setState(() {
distance = value;
});
},
),
Container(
margin: EdgeInsets.only(left: 25, right: 25, top: 40),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(widget.minDistance.toInt().toString()),
Text(widget.maxDistance.toInt().toString())
],
),
),
],
),
),
);
}
}
class SliderThumbImage extends SliderComponentShape {
final ui.Image image;
final double thumbRadius;
final int max;
SliderThumbImage({this.image, this.thumbRadius, this.max});
@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,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value}) {
final canvas = context.canvas;
final imageWidth = image?.width ?? 10;
final imageHeight = image?.height ?? 10;
Offset imageOffset = Offset(
center.dx - (imageWidth / 2),
center.dy - (imageHeight / 0.935),
);
Paint paint = Paint()..filterQuality = FilterQuality.high;
if (image != null) {
canvas.drawImage(image, imageOffset, paint);
}
TextSpan span = new TextSpan(
style: new TextStyle(
fontSize: imageHeight * .3,
fontWeight: FontWeight.w700,
color: sliderTheme.valueIndicatorColor,
height: 0.9),
text: '${getValue(value)}');
TextPainter tp = new TextPainter(
text: span,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr);
tp.layout();
Offset textCenter = Offset(
center.dx - (tp.width / 2),
center.dy - (tp.height / 0.32),
);
tp.paint(canvas, textCenter);
}
String getValue(double value) {
return ((max * value).round()).toString();
}
}