flutter开发实战-自定义Switch开关控件Widget

flutter开发实战-自定义Switch开关控件
在flutter中实现自定义Switch,主要实现类似IOS的UISwitch样式的开关控件

一、效果图

在这里插入图片描述

二、实现Switch开关的Widget

实现自定义Switch的Widget,主要实现交织动画。
交织动画
有些时候我们可能会需要一些复杂的动画,这些动画可能由一个动画序列或重叠的动画组成。一个动画组合在不同阶段包含了多种动画,要实现这种效果,需要使用交织动画(Stagger Animation)实现会比较方法。

Stagger Animation

  • 1、使用多个动画对象(Animation)。
  • 2、多个Animation使用同一个AnimationController控制。
  • 3、需要设置每一个动画对象指定时间间隔(Interval)

这里实现自定义Switch的Widget用到了colorAnimation,positionAnimation,更改颜色动画及位置动画。多个动画的时候需要在Widget中添加TickerProviderStateMixin。通过TickerProviderStateMixin实现TickerProvider获取对象的通知。TickerProvider来控制Ticker的通知,Ticker可以应用在Flutter中的每个对象上,一旦某个对象实现了Ticker的功能,每次动画帧改变,屏幕重绘时就会通知这个对象。

自定义Switch定义了onChanged实现将开关callback到使用的Widget上。

具体代码实现如下

/// 定制switch
class CustomSwitch extends StatefulWidget {const CustomSwitch({Key? key,required this.value,this.bgColor,this.bgBorderColor,this.bgOpenBorderColor,this.bgBorderWidth,this.openBgColor,this.color,this.openColor,this.width,this.height,this.borderColor,this.openBorderColor,this.borderWidth,required this.onChanged,}) : super(key: key);final bool value;final double? width;final double? height;final Color? bgBorderColor;final Color? bgOpenBorderColor;final double? bgBorderWidth;final Color? bgColor;final Color? openBgColor;final Color? color;final Color? openColor;final Color? borderColor;final Color? openBorderColor;final double? borderWidth;final ValueChanged<bool>? onChanged;State<CustomSwitch> createState() => _CustomSwitchState();
}class _CustomSwitchState extends State<CustomSwitch>with TickerProviderStateMixin {late AnimationController _controller;late Animation<double> _positionAnimation;late Animation<Color?> _colorAnimation;late Animation<Color?> _bgColorAnimation;late Animation<Color?> _bgBorderColorAnimation;late Animation<Color?> _borderColorAnimation;bool _switchOpen = false;Color _bgColor = Colors.black12;Color _openBgColor = Colors.lightBlueAccent;Color _color = Colors.black26;Color _openColor = Colors.lightBlue;Color _bgBorderColor = Colors.black12;Color _bgOpenBorderColor = Colors.lightBlueAccent;Color _borderColor = Colors.black12;Color _openBorderColor = Colors.lightBlue;double _width = 50.0;double _height = 30.0;double _minSize = 30.0;bool _isAnimating = false; // 动画中double _space = 2.0;bool _isStartAnimating = false;void initState() {// TODO: implement initState_switchOpen = widget.value;_bgColor = widget.bgColor ?? Colors.black12;_openBgColor = widget.openBgColor ?? Colors.lightBlueAccent;_color = widget.color ?? Colors.blueGrey;_openColor = widget.openColor ?? Colors.lightBlue;_bgBorderColor = widget.bgBorderColor ?? Colors.black12;_bgOpenBorderColor = widget.bgOpenBorderColor ?? Colors.lightBlueAccent;_borderColor = widget.borderColor ?? Colors.black12;_openBorderColor = widget.openBorderColor ?? Colors.lightBlue;if (widget.width != null && widget.height != null) {_width = widget.width!;_height = widget.height!;}_minSize = min(_width, _height) - _space;super.initState();runAnimation();}void runAnimation() {Color _bgBeginColor;Color _bgEndColor;Color _beginColor;Color _endColor;double _beginP;double _endP;Color _bgBorderBeginColor;Color _bgBorderEndColor;Color _borderBeginColor;Color _borderEndColor;if (_switchOpen) {_bgBeginColor = _openBgColor;_bgEndColor = _bgColor;_beginColor = _openColor;_endColor = _color;_bgBorderBeginColor = _bgOpenBorderColor;_bgBorderEndColor = _bgBorderColor;_borderBeginColor = _openBorderColor;_borderEndColor = _borderColor;_beginP = _width - _minSize - _space;_endP = _space;} else {_bgBeginColor = _bgColor;_bgEndColor = _openBgColor;_beginColor = _color;_endColor = _openColor;_bgBorderBeginColor = _bgBorderColor;_bgBorderEndColor = _bgOpenBorderColor;_borderBeginColor = _borderColor;_borderEndColor = _openBorderColor;_beginP = _space;_endP = _width - _minSize - _space;}_controller =AnimationController(vsync: this, duration: Duration(milliseconds: 200));// 移动位置_positionAnimation = Tween<double>(begin: _beginP,end: _endP,).animate(CurvedAnimation(parent: _controller,curve: Interval(0.0, 1.0, //间隔,后20%的动画时间curve: Curves.ease,),),);_colorAnimation = ColorTween(begin: _beginColor,end: _endColor,).animate(CurvedAnimation(parent: _controller,curve: const Interval(0.0, 1.0, //间隔,前60%的动画时间curve: Curves.ease,),),);_bgColorAnimation = ColorTween(begin: _bgBeginColor,end: _bgEndColor,).animate(CurvedAnimation(parent: _controller,curve: const Interval(0.0, 1.0, //间隔,前60%的动画时间curve: Curves.ease,),),);_bgBorderColorAnimation = ColorTween(begin: _bgBorderBeginColor,end: _bgBorderEndColor,).animate(CurvedAnimation(parent: _controller,curve: const Interval(0.0, 1.0, //间隔,前60%的动画时间curve: Curves.ease,),),);_borderColorAnimation = ColorTween(begin: _borderBeginColor,end: _borderEndColor,).animate(CurvedAnimation(parent: _controller,curve: const Interval(0.0, 1.0, //间隔,前60%的动画时间curve: Curves.ease,),),);_controller.addListener(() {if (mounted) {setState(() {});}});_controller.addStatusListener((status) {if (status == AnimationStatus.completed) {_isAnimating = false;_isStartAnimating = true;// 完成if (widget.onChanged != null) {widget.onChanged!(!_switchOpen);}}});}void animationDispose() {_controller.dispose();}void onSwitchPressed() {if (_isAnimating) {return;}_isAnimating = true;if (_isStartAnimating) {_switchOpen = !_switchOpen;}runAnimation();_controller.forward();}void dispose() {// TODO: implement disposeanimationDispose();super.dispose();}Widget build(BuildContext context) {double radius = _minSize / 2.0;double bgRadius = _height / 2.0;return GestureDetector(onTap: () {onSwitchPressed();},child: Container(width: _width,height: _height,child: Stack(alignment: Alignment.center,children: [Container(width: _width,height: _height,decoration: BoxDecoration(color: _bgColorAnimation.value,borderRadius: BorderRadius.circular(bgRadius),border: Border.all(color: _bgBorderColorAnimation.value ?? Colors.transparent,width: widget.bgBorderWidth ?? 0,style: BorderStyle.solid,),),),Positioned(left: _positionAnimation.value,child: Container(width: _minSize,height: _minSize,decoration: BoxDecoration(color: _colorAnimation.value,borderRadius: BorderRadius.circular(radius),border: Border.all(color: _borderColorAnimation.value ?? Colors.transparent,width: widget.borderWidth ?? 0,style: BorderStyle.solid,),),),),],),),);}
}

三、小结

flutter开发实战-自定义Switch开关控件,主要交织动画(Stagger Animation),通过控制不同的动画来实现类似iOS中的UISwitch控件样式。

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/14836.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV在一个图像上画一个空心绿色的圆和一个实心红色的圆

/*** void cvCircle( CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int line_type=8, int shift=0 );* Opencv画点 其实画的是小圆圈* img:图像。* center:圆心坐标。* radius:圆形的半径。* color:线条的颜色。* thickness:如果是正数,表…

了解k8s容器组pods

一&#xff1a;Pods概述 在 部署第一个应用程序 中创建 Deployment 后&#xff0c;k8s创建了一个 Pod&#xff08;容器组&#xff09; 来放置应用程序实例&#xff08;container 容器&#xff09; Pod 容器组 是一个k8s中一个抽象的概念&#xff0c;用于存放一组 container&a…

文字和祝福语:创意的粒子效果网页(❤️好看好用❤️)HTML+CSS+JS

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

Stable Diffusion 多角度人设立绘快速生成多种方法

对于插画师构建人物立绘图设计一套多方位的人设可能要很久&#xff0c;但是使用SD进行操作的话就非常简单了&#xff0c;这个利用ControlNet骨骼图进行配置操作。 供一些样图参考&#xff0c;也可以使用ADetailer进行人物相关部位的修复。 文章目录 准备工作关键词绘制使用骨骼…

Git--远程操作

文章目录 前言一、理解分布式版本控制系统二、远程仓库1.新建远程仓库2.克隆远程仓库3.向远程仓库推送4.拉取远程仓库5.配置Git忽略特殊文件 给命令配置别名 总结 前言 正文开始!!! 一、理解分布式版本控制系统 我们目前所说的所有内容(工作区,暂存区,版本库等等),都是在本地…

数据库-SQL-DML语句

文章目录 DML语句添加数据修改数据DML-删除数据 DML语句 添加数据 表的结构 修改数据 DML-删除数据 DML-总结&#xff1a;

【Redis】2、Redis 的 Java 客户端(Jedis 和 SpringDataRedis)

目录 零、Redis 的 Java 客户端有哪些&#xff1f;二、Jedis 客户端(1) 引依赖(2) 连接 Redis 服务并测试(3) Redis 连接池 三、SpringDataRedis 介绍四、SpringBoot 中集成 SpringDataRedis(1) 引入依赖(2) 配置文件中书写相关配置(3) RedisTemplate 的默认序列化方式(4) 自定…

Qt保存代码

补全保存代码 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//字体按钮对应的槽函数 void Widget::on_fontBtn_clicked() {…

TCP 协议报文

TCP 提供面向连接的通信传输&#xff0c;面向连接是指在传送数据之前必须先建立连接&#xff0c;数据传送完成后要释放连接。无论哪一方向另一方发送数据之前&#xff0c;都必须先在双方之间建立一条连接。在TCP/IP协议中&#xff0c;TCP协议提供可靠的连接服务&#xff0c;连接…

Adobe中修改注释签名

控制面板-> 系统和安全-> 管理工具-> 计算机管理-> 打开“计算机管理”对话框-> 在左边栏的系统工具下选择本地用户和组-> 点击“用户”->选择要改的用户名->右键重命名 打开Adobe Acrobat->点击"编辑"->首选项->注释 ->把 “登…

交叉导轨的结构与特长

在交叉导轨中&#xff0c;精密滚柱互相直交地组合在一起的滚柱保持架与设置在专用轨道上的90V形沟槽滚动面组合起来使用。通过将2列滚子导轨平行地装配&#xff0c;使导轨系统能承受4个方向的负荷。而且&#xff0c;因能向交叉滚子导轨施加预压&#xff0c;从而能获得无间隙且高…

七、VPN技术之密码学基础(密码体制、对称加密算法、非对称加密算法)

更多网络基础内容可见: 网络基础学习目录及各章节指引 7.1 密码学基础 7.1.1 基础概念 密码:对文本进行编码,使偷窥者无法识别的算法。是一套编码方案,一种特殊的报文编码和相应的解码方式的结合体。 加密之前的原始报文称为明文,使用密码之后的报文叫密文。一个简单的例…