标签:动画 const controller key child override
UI 界面设计合理的动画,可以让用户觉得更加流畅、直观,可以极大提高和改善用户体验 实现原理 动画就是动起来的画面 视觉暂留:画面经视神经传入大脑后,不会立即消失(会存留一段时间) 帧(Frame):单个的画面,在学术上叫帧 每秒钟展示的帧数简称 fps (Frame per Second) 动画分类补间(Tween)动画 在补间动画中,我们定义开始点和结束点、时间线以及定义转换时间和速度曲线。然后由系统计算,从开始点运动到结束点。 从而形成动画效果。例如:透明度从 0 到 1,颜色值从 0 到 255
拟物动画 拟物动画是对真实世界的行为进行建模,使动画效果类似于现实中的物理效果。例如:弹簧、阻尼、重力、抛物线等
动画 - Animation
Animation,是 Flutter 动画库中的一个核心类。它包含动画的值和状态两个属性,定义了动画的一系列监听函数。
监听值: addListener removeListener
监听状态: addStatusListener removeStatusListener
动画状态 AnimationStatus.dismissed -- 动画初始状态 AnimationStatus.completed -- 动画结束状态 AnimationStatus.forward -- 动画处在从开始到结束的运行状态 AnimationStatus.reverse -- 动画处在从结束到开始的运行状态
动画 - AnimationController AnimationController(动画控制器) 在指定时间内,将组件属性值由初始值演变到终止值。从而形成动画效果 AnimationController 参数 duration(动画的执行时间) reverseDuration(动画反向执行时间) lowerBound = 0.0 (动画最小值) upperBound = 1.0(动画最大值) value (动画初始值,默认是 lowerBound) vsync (TickerProvider 类型的对象,用来创建 Ticker 对象) 当创建一个 AnimationController 时,需要传递一个 vsync 参数 vsync 的作用是:防止屏幕外动画(动画页面切换到后台时)消耗不必要的资源 通过将 SingleTickerProviderStateMixin 添加到类定义中,可以将 stateful 对象作为 vsync 的值 AnimationController 具有控制动画的方法: .forward() 可以正向执行动画 .reverse() 可以反向执行动画 .dispose() 用来释放动画资源(在不使用时需要调用该方法,否则会造成资源泄漏) .stop() 用来停止动画运行
动画 - Tween 简介 AnimationController 动画生成值的默认区间是 0.0 到 1.0,如果希望使用不同的区间,或不同的数据类型,需要使用 Tween(补间动画) Tween 的唯一职责就是定义从 输入范围 到 输出范围的映射,例如:颜色区间是 0 到 255 Tween Tween<double>(begin:起始值,end:终止值); ColorTween(begin: Colors.white, end: Colors.black);
动画 - CurvedAnimation 简介 动画执行的速度有多种(匀速、先快后慢或先慢后快)这里的速度称为动画曲线 CurvedAnimation 的目的是为 AnimationController 添加动画曲线 组件 CurvedAnimation(parent: controller, curve: Curves.easeIn) parent(动画控制器对象) curve(正向执行的动画曲线) reverseCurve(反向执行的动画曲线) Curves 动画曲线:https://api.flutter-io.cn/flutter/animation/Curves-class.html
动画 - 步骤 (1)、创建动画控制器 controller = AnimationController(duration, vsync) (2)、创建动画 动画曲线(CurvedAnimation) 补间动画(Tween) (3)、监听动画 addListener(); // 监听动画生成值 addStatusListener(); // 监听动画状态 (4)、执行动画 controller.forward(); // 正向执行 controller.reverse(); // 反向执行
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Animation'), ), body: const AnimationDemo(), ); } } class AnimationDemo extends StatefulWidget { const AnimationDemo({Key? key}) : super(key: key); @override State<AnimationDemo> createState() => _AnimationDemoState(); } class _AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin { late AnimationController controller; late Animation animation; @override void initState() { // TODO: implement initState super.initState(); // 1、创建 AnimationController controller = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); // 2-1、声明动画曲线 animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn); // 2-2、设置动画值的范围 animation = Tween(begin: 50.0, end: 200.0).animate(controller); // 3、监听动画 animation.addListener(() { setState(() {}); }); // 4、执行动画 controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Column( children: [ ElevatedButton( onPressed: () { controller.forward(); }, child: const Text('放大'), ), ElevatedButton( onPressed: () { controller.reverse(); }, child: const Text('缩小'), ), ElevatedButton( onPressed: () { animation.addStatusListener((status) { print('status: $status'); if (status == AnimationStatus.completed) { // 反向执行动画 controller.reverse(); } else if (status == AnimationStatus.dismissed) { // 正向执行动画 controller.forward(); } }); controller.forward(); }, child: const Text('重复'), ), ElevatedButton( onPressed: () { controller.stop(); }, child: const Text('停止'), ), Icon( Icons.favorite, color: Colors.red, size: animation.value, ), Opacity( opacity: controller.value, child: const Text('Hello Flutter'), ), ], ), ); } @override void dispose() { // TODO: implement dispose super.dispose(); controller.dispose(); } }
交织动画 What? 交织动画是由多个单一动画叠加而成的复杂动画 例如:组件变化可能涉及高度、宽度、颜色、透明度、位置等等 需要给每个动画设置时间间隔(Interval)
Transform(对组件进行矩阵变换) 平移:Transform.translate() 旋转:Transform.rotate() 缩放:Transform.scale()
import 'package:flutter/material.dart'; import 'dart:math'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Stagger Animation'), leading: const Icon(Icons.menu), actions: const [Icon(Icons.settings)], elevation: 0.0, centerTitle: true, ), body: const AnimationDemo(), ); } } class AnimationDemo extends StatefulWidget { const AnimationDemo({Key? key}) : super(key: key); @override State<AnimationDemo> createState() => _AnimationDemoState(); } class _AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin { late AnimationController controller; late Animation<double> animation; late Animation sizeAnimation; late Animation colorAnimation; late Animation rotationAnimation; @override void initState() { // TODO: implement initState super.initState(); // 1、创建 AnimationController controller = AnimationController( vsync: this, duration: const Duration(seconds: 3), ); // 2、创建动画 animation = CurvedAnimation( parent: controller, curve: const Interval(0.0, 0.5), )..addListener(() { setState(() {}); }); // 3、让动画反复执行 animation.addStatusListener((status) { if (status == AnimationStatus.completed) { // 反向执行动画 controller.reverse(); } else if (status == AnimationStatus.dismissed) { // 正向执行动画 controller.forward(); } }); // 4、设置其它动画 sizeAnimation = Tween(begin: 0.0, end: 200.0).animate(animation); colorAnimation = ColorTween(begin: Colors.yellow, end: Colors.red).animate( CurvedAnimation( parent: controller, curve: const Interval(0.5, 0.8, curve: Curves.bounceIn), )..addListener(() { setState(() {}); }), ); rotationAnimation = Tween(begin: 0.0, end: 2 * pi).animate( CurvedAnimation( parent: controller, curve: const Interval(0.8, 1.0, curve: Curves.easeIn), ), ); } @override Widget build(BuildContext context) { return Center( child: Column( children: [ ElevatedButton( child: const Text('重复'), onPressed: () { animation.addStatusListener((status) { print('status, $status'); if (status == AnimationStatus.completed) { // 反向执行动画 controller.reverse(); } else if (status == AnimationStatus.dismissed) { // 正向执行动画 controller.forward(); } }); controller.forward(); }, ), ElevatedButton( onPressed: () { controller.stop(); }, child: const Text('停止'), ), Icon( Icons.favorite, color: Colors.red, size: sizeAnimation.value, ), Opacity( opacity: controller.value, child: Transform.rotate( angle: rotationAnimation.value, child: Container( width: sizeAnimation.value, height: sizeAnimation.value, color: colorAnimation.value, ), ), ), ], ), ); } @override void dispose() { // TODO: implement dispose super.dispose(); controller.dispose(); } }
Hero 动画 Hero 动画用来实现跨页面的动画效果 在不同页面中,声明一个共享组件(Hero) 由于共享组件在不同页面中的位置、外观等不同,路由切换时,形成动画效果
如何实现 在页面A中定义起始 Hero 组件(source hero),声明 tag 在页面B中定义 目标 Hero 组件(destination hero),绑定相同的 tag 页面跳转时,通过 Navigator,传递 tag
Hero 组件 tag(路由切换时,共享组件的标记) child(声明子组件)
// image_detail.dart import 'package:flutter/material.dart'; class ImageDetail extends StatelessWidget { final String imageUrl; const ImageDetail({ Key? key, this.imageUrl = '', }) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: Center( child: GestureDetector( onTap: () { // 返回 Navigator.pop(context); }, child: Hero( tag: imageUrl, child: Image.network( imageUrl, width: double.infinity, fit: BoxFit.cover, ), ), ), ), ); } }
import 'package:flutter/material.dart'; import 'image_detail.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Hero Animation'), ), body: const HeroAnimation(), ); } } class HeroAnimation extends StatefulWidget { const HeroAnimation({Key? key}) : super(key: key); @override State<HeroAnimation> createState() => _HeroAnimationState(); } class _HeroAnimationState extends State<HeroAnimation> { @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(10), child: GridView.extent( maxCrossAxisExtent: 200.0, // 子组件最大宽度 mainAxisSpacing: 20, children: List.generate(20, (index) { String imageUrl = 'https://picsum.photos/id/$index/300/400'; return GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (BuildContext ctx) { return ImageDetail(imageUrl: imageUrl); })); }, child: Hero( child: Image.network(imageUrl), tag: imageUrl, ), ); }), ), ); } }
标签:动画,const,controller,key,child,override 来源: https://www.cnblogs.com/rogerwu/p/16427894.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。