【Flutter学习笔记】10.3 组合实例:TurnBox

2024-03-23 04:52

本文主要是介绍【Flutter学习笔记】10.3 组合实例:TurnBox,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考资料:《Flutter实战·第二版》 10.3 组合实例:TurnBox


这里尝试实现一个更为复杂的例子,其能够旋转子组件。Flutter中的RotatedBox可以旋转子组件,但是它有两个缺点:

  • 一是只能将其子节点以90度的倍数旋转
  • 二是当旋转的角度发生变化时,旋转角度更新过程没有动画

因此,这里将自定义一个TurnBox,不仅可以设置任意角度旋转的子Widget,还能再角度发生改变时执行一个过渡动画,同时,还可以手动设置动画的执行时长。
首先,组件一定是一个动画组件,需要实现SingleTickerProviderStateMixin并设置Controler对象,这里没有定义AnimationController对象,直接在Controler内部设置起始值,默认值是[0, 1],类型为浮点数。输入参数有旋转的多少、旋转动画的时长和子Widget,其具有默认的初始值。
在组件初始化阶段,首先定义_controller,其取值范围为 [ − ∞ , + ∞ ] [-\infin,+\infin] [,+],并将其初始值设为传入参数,否则为默认值0。
组件通过RotationTransition构建,需传入一个Animation<double>对象并设置子Widget。
当外部传入的参数turnsspeed变化时(turns为主要控制变量),则执行动画到目标状态。
注意在组件销毁的dispose()函数当中销毁_controller防止内存泄漏的问题。

class TurnBox extends StatefulWidget {const TurnBox({Key? key,this.turns = .0, //旋转的“圈”数,一圈为360度,如0.25圈即90度this.speed = 200, //过渡动画执行的总时长this.child}) :super(key: key);final double turns;final int speed;final Widget? child;TurnBoxState createState() => TurnBoxState();
}class TurnBoxState extends State<TurnBox>with SingleTickerProviderStateMixin {late AnimationController _controller;void initState() {super.initState();_controller = AnimationController(vsync: this,lowerBound: -double.infinity,upperBound: double.infinity);_controller.value = widget.turns;}void dispose() {_controller.dispose();super.dispose();}Widget build(BuildContext context) {return RotationTransition(turns: _controller,child: widget.child,);}void didUpdateWidget(TurnBox oldWidget) {super.didUpdateWidget(oldWidget);//旋转角度发生变化时执行过渡动画if (oldWidget.turns != widget.turns) {_controller.animateTo(widget.turns,duration: Duration(milliseconds: widget.speed??200),curve: Curves.easeOut,);}}
}

下面可以测试一下定义好组件的功能,大小两个组件全部采用一个state控制,但是旋转速度不同,大的会慢一些:

class TurnBoxRoute extends StatefulWidget {const TurnBoxRoute({Key? key}) : super(key: key);TurnBoxRouteState createState() => TurnBoxRouteState();
}class TurnBoxRouteState extends State<TurnBoxRoute> {double _turns = .0;Widget build(BuildContext context) {return Center(child: Column(mainAxisSize: MainAxisSize.min,children: <Widget>[TurnBox(turns: _turns,speed: 500,child: const Icon(Icons.refresh,size: 50,),),TurnBox(turns: _turns,speed: 1000,child: const Icon(Icons.refresh,size: 150.0,),),ElevatedButton(child: const Text("顺时针旋转1/5圈"),onPressed: () {setState(() {_turns += .2;});},),const SizedBox(height: 10,),ElevatedButton(child: const Text("逆时针旋转1/5圈"),onPressed: () {setState(() {_turns -= .2;});},)],),);}
}

在这里插入图片描述
这部分内容最常用到的函数就是didUpdateWidget(),其在传入参数发生变化时调用。例如我们要实现一个解析url链接的富文本文件,那么在一开始要对传入的文本进行解析,而后才能生成对应的Widget。解析的过程与构建过程分开较为合适,可以保证UI发生变化时,所需的文本不会被反复解析,以减少不必要的耗时,因此放在initState()中是一个不错的选择。但是,当传入的参数发生变化时(组件树结构改变),initState()并不执行,文本内容不会更新。因此,可以将解析过程放在didUpdateWidget()中,这样当参数变化时,能够及时对UI进行重构:

class _MyRichTextState extends State<MyRichText> {TextSpan _textSpan;Widget build(BuildContext context) {return RichText(text: _textSpan,);}TextSpan parseText(String text) {// 耗时操作:解析文本字符串,构建出TextSpan。// 省略具体实现。}void initState() {_textSpan = parseText(widget.text)super.initState();}void didUpdateWidget(MyRichText oldWidget) {if (widget.text != oldWidget.text) {_textSpan = parseText(widget.text);}super.didUpdateWidget(oldWidget);}
}

虽然这看起来是一个简单的方式,但是在实际开发过程中很容易被忽略,一定要注意传入参数是否会经常发生改变,及时更新输入状态。

这篇关于【Flutter学习笔记】10.3 组合实例:TurnBox的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/837188

相关文章

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析

《Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析》InstantiationAwareBeanPostProcessor是Spring... 目录一、什么是InstantiationAwareBeanPostProcessor?二、核心方法解

java String.join()方法实例详解

《javaString.join()方法实例详解》String.join()是Java提供的一个实用方法,用于将多个字符串按照指定的分隔符连接成一个字符串,这一方法是Java8中引入的,极大地简化了... 目录bVARxMJava String.join() 方法详解1. 方法定义2. 基本用法2.1 拼接

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创

Java List排序实例代码详解

《JavaList排序实例代码详解》:本文主要介绍JavaList排序的相关资料,Java排序方法包括自然排序、自定义排序、Lambda简化及多条件排序,实现灵活且代码简洁,文中通过代码介绍的... 目录一、自然排序二、自定义排序规则三、使用 Lambda 表达式简化 Comparator四、多条件排序五、