当前位置: 首页 > news >正文

04_Flutter自定义Slider滑块

04_Flutter自定义Slider滑块

一.Slider控件基本用法
Column(mainAxisAlignment: MainAxisAlignment.start,children: <Widget>[Text("sliderValue: ${_sliderValue.toInt()}"),Slider(value: _sliderValue,min: 0,max: 100,divisions: 10,thumbColor: Colors.red,activeColor: Colors.red,onChanged: (value) {setState(() {_sliderValue = value;});})],
)

在这里插入图片描述

const Slider({super.key,required this.value,this.secondaryTrackValue,required this.onChanged,this.onChangeStart,this.onChangeEnd,this.min = 0.0,this.max = 1.0,this.divisions,this.label,this.activeColor,this.inactiveColor,this.secondaryActiveColor,this.thumbColor,this.overlayColor,this.mouseCursor,this.semanticFormatterCallback,this.focusNode,this.autofocus = false,})

几个比较重要的属性:

  • value:slider控件显示的值
  • min:slider控件滑动到最左边对应的值,即最小值
  • max: slider控件滑动到最右边对应的值,即最大值
  • divisions: 最小值到最大值之间被几等分
  • activeColor: 滑块划过部分的颜色值,即选中的颜色值
  • inactiveColor:滑块未划过部分的颜色值,即为选中的颜色值
  • thumbColor:滑块的颜色值
二.如何修改滑块的大小以及滑块轨迹的高度

从上面的示例可以看到,通过Slider控件为我们提供的属性,只支持改变滑块的颜色,以及滑块轨迹的颜色,那么我们想要改变滑块的大小以及滑块轨迹的高度,是不是只能重新自定义呢?

NO! NO! NO!,细心的您在使用Flutter的AppBar时,可能会发现,为AppBar控件指定样式时,除了使用AppBar控件提供的属性外,也可以使用AppBarTheme来为AppBar设置某些特定的样式,既然如此,不妨查看下Flutter sdk的源码与Slider对应的是否有一个叫SliderTheme的控件呢? 嘿嘿,还真有。

final SliderThemeData data;
const SliderTheme({super.key,required this.data,required super.child,
});const SliderThemeData({this.trackHeight,this.thumbShape,...
});

仔细找SliderThemeData的trackHeight以及thumbShape的属性注释:

/// The height of the [Slider] track.
final double? trackHeight;/// The shape that will be used to draw the [Slider]'s thumb.
/// The default value is [RoundSliderThumbShape].
final SliderComponentShape? thumbShape;

此处省略…翻译软件的时间:

  • trackHeight:[滑块]轨迹的高度
  • thumbShape:默认值是一个RoundSliderThumbShape对象

看下RoundSliderThumbShape的源码怎么写的:

const RoundSliderThumbShape({this.enabledThumbRadius = 10.0,this.disabledThumbRadius,this.elevation = 1.0,this.pressedElevation = 6.0,
});

看到这里就不用做过多的解释了吧😂,因此要修改滑块的大小,可以重新指定thumbShape为RoundSliderThumbShape对象,并设置enabledThumbRadius的值。

在这里插入图片描述

Column(mainAxisAlignment: MainAxisAlignment.start,children: <Widget>[Text("sliderValue: ${_sliderValue.toInt()}"),SliderTheme(data: const SliderThemeData(trackHeight: 20,thumbShape: RoundSliderThumbShape(enabledThumbRadius: 20)),child: Slider(value: _sliderValue,min: 0,max: 100,divisions: 10,thumbColor: Colors.red,activeColor: Colors.red,onChanged: (value) {setState(() {_sliderValue = value;});}))],
)
三.使用本地资源图片作为自定义滑块

既然要自定义滑块,毫无疑问需要从SliderThemeData的thumbShape入手。

final SliderComponentShape? thumbShape;

thumbShape的类型为SliderComponentShape,继续查看SliderComponentShape源码:

abstract class SliderComponentShape {const SliderComponentShape();Size getPreferredSize(bool isEnabled, bool isDiscrete);void paint(PaintingContext context,Offset center, {required Animation<double> activationAnimation,required Animation<double> enableAnimation,required bool isDiscrete,required TextPainter labelPainter,required RenderBox parentBox,required SliderThemeData sliderTheme,required TextDirection textDirection,required double value,required double textScaleFactor,required Size sizeWithOverflow,});
}

因此我们可以定义一个类继承SliderComponentShape,并实现getPreferredSize和paint方法,getPreferredSize控制滑块大小,paint负责把滑块绘制到屏幕上。

  • 首先第一步我们需要将本地图片为一个ImageInfo,例如传入一个"lib/assets/images/ic_slider_thumb.png",最后得到一个ImageInfo,这里就直接奉上源码了,其实现也是参考了Image.asset的源码:
typedef AssertsWidgetBuilder = Widget Function(BuildContext context, ImageInfo? imageInfo);class AssertsImageBuilder extends StatefulWidget {final String assertsName;final AssertsWidgetBuilder builder;const AssertsImageBuilder(this.assertsName,{super.key,required this.builder,});State<StatefulWidget> createState() => _AssertsImageBuilderState();}class _AssertsImageBuilderState extends State<AssertsImageBuilder> {ImageInfo? _imageInfo;void initState() {super.initState();_loadAssertsImage().then((value) {setState(() {_imageInfo = value;});});}void didUpdateWidget(covariant AssertsImageBuilder oldWidget) {super.didUpdateWidget(oldWidget);if(oldWidget.assertsName != widget.assertsName) {_loadAssertsImage().then((value) {setState(() {_imageInfo = value;});});}}Widget build(BuildContext context) {return widget.builder!.call(context, _imageInfo);}Future<ImageInfo?> _loadAssertsImage() {final Completer<ImageInfo?> completer = Completer<ImageInfo?>();WidgetsBinding.instance.addPostFrameCallback((timeStamp) {final ImageProvider imageProvider = AssetImage(widget.assertsName);final ImageConfiguration config = createLocalImageConfiguration(context);final ImageStream stream = imageProvider.resolve(config);ImageStreamListener? listener;listener = ImageStreamListener((ImageInfo? image, bool sync) {if (!completer.isCompleted) {completer.complete(image);}SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {stream.removeListener(listener!);});},onError: (Object exception, StackTrace? stackTrace) {stream.removeListener(listener!);completer.completeError(exception, stackTrace);},);stream.addListener(listener);});return completer.future;}}
  • 自定义SliderComponentShape
import 'package:flutter/material.dart';
import 'dart:ui' as ui;class ImageSliderThumb extends SliderComponentShape {final Size size;final ui.Image? image;const ImageSliderThumb({required this.image,Size? size}): size = size ?? const Size(20, 20);Size getPreferredSize(bool isEnabled, bool isDiscrete) {return size;}void paint(PaintingContext context, Offset center, {required Animation<double> activationAnimation, required Animation<double> enableAnimation, required bool isDiscrete, required TextPainter labelPainter, required RenderBox parentBox, required SliderThemeData sliderTheme, required TextDirection textDirection, required double value, required double textScaleFactor, required Size sizeWithOverflow}) {}}
  • 绘制图片滑块

void paint(PaintingContext context, Offset center, {required Animation<double> activationAnimation, required Animation<double> enableAnimation, required bool isDiscrete, required TextPainter labelPainter, required RenderBox parentBox, required SliderThemeData sliderTheme, required TextDirection textDirection, required double value, required double textScaleFactor, required Size sizeWithOverflow}) {//图片中心点double dx = size.width/2;double dy = size.height/2;if(image != null) {final Rect sourceRect = Rect.fromLTWH(0, 0, image!.width.toDouble(), image!.width.toDouble());//center会随着滑块的移动而改变,所以这里需要根据center计算图片绘制的位置double left = center.dx - dx;double top = center.dy - dy;double right = center.dx + dx;double bottom = center.dy + dy;Rect destinationRect = Rect.fromLTRB(left, top, right, bottom);final Canvas canvas = context.canvas;final Paint paint = new Paint();paint.isAntiAlias = true;//绘制滑块canvas.drawImageRect(image!, sourceRect, destinationRect, paint);}
}
四.怎么使用?
Column(mainAxisAlignment: MainAxisAlignment.start,children: <Widget>[Text("sliderValue: ${_sliderValue.toInt()}"),AssertsImageBuilder("lib/assets/images/ic_slider_thumb.png",builder: (context, imageInfo) {return SliderTheme(data: SliderThemeData(trackHeight: 10,thumbShape: ImageSliderThumb(image: imageInfo?.image,size: const Size(30, 30))),child: Slider(value: _sliderValue,min: 0,max: 100,divisions: 10,thumbColor: Colors.red,activeColor: Colors.red,onChanged: (value) {setState(() {_sliderValue = value;});}));}),],
)

在这里插入图片描述

http://www.lryc.cn/news/248778.html

相关文章:

  • 服务器数据恢复—EMC存储raid5故障导致上层应用崩溃的数据恢复案例
  • 7.1 Windows驱动开发:内核监控进程与线程回调
  • 基于ssm的汽车论坛管理系统设计与实现
  • 实习开发日志经验总结(一)
  • 【Unity基础】8.简单场景的搭建
  • 傅里叶变换及其在机器学习中的应用
  • xorm源码学习
  • Vue3中的<script setup>和<script>的区别
  • Docker笔记-Docker搭建最新版zabbix服务端(2023-07-31)
  • QT配合CSS隐藏按钮
  • 2023亚太地区数学建模C题思路分析+模型+代码+论文
  • Linguistic Steganalysis in Few-Shot Scenario论文阅读笔记
  • 详细学习Pyqt5的4种项目部件(Item Widget)
  • notepad++ 插件JSONView安装
  • AKConv:具有任意采样形状和任意数目参数的卷积核
  • 如何使用C++开发集群服务
  • docker安装以及idea访问docker
  • 激光切割头组件中喷嘴的作用是什么
  • 腾讯云双11活动最后一天,错过再等一年!
  • Java实现飞翔的鸟小游戏
  • Python网络请求初级篇:使用Requests库抓取和解析数据
  • 详解API开发【电商平台API封装商品详情SKU数据接口开发】
  • 后端项目连接数据库-添加MyBatis依赖并检测是否成功
  • C++ CryptoPP使用RSA加解密
  • 从实践角度深入探究数据驱动和关键字驱动测试方法!
  • Unity收费对谁影响最大
  • 信号收尾.
  • maven 常用命令解析
  • ESP32-Web-Server编程-JS 基础 1
  • 代码随想录算法训练营第23天|● 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树 ● 总结篇