Flutter实现心动的动画特效

作者:艾维码 时间:2021-09-03 18:08:01 

为了追求更好的用户体验,有时候我们需要一个类似心跳一样跳动着的控件来吸引用户的注意力,这是一个小小的优化需求,但是在 Flutter 里动画两件套就像裹脚布一样臭长,所以需要像封装一个 AnimatedWidget,解放生产力。

实现动画

混入 SingleTickerProviderStateMixin

当创建一个 AnimationController 时,需要传递一个vsync参数,存在vsync时会防止动画的UI不在当前屏幕时消耗不必要的资源。 通过混入 SingleTickerProviderStateMixin 。

class _MyHomePageState extends State<MyHomePage>  with SingleTickerProviderStateMixin{}

创建动画

创建一个间隔将近一秒钟的动画控制器:

late final AnimationController animController;

@override
 void initState() {
   super.initState();
   animController = AnimationController(
     duration: const Duration(milliseconds: 800),
     vsync: this,
   );
   }

心跳动画是从小变大,再变小,所以需要一个值大小变化的动画:

late final Animation<double> animation;

@override
 void initState() {
   super.initState();
   animController = AnimationController(
     duration: const Duration(milliseconds: 800),
     vsync: this,
   );
    animation = Tween<double>(
     begin: 0.9,
     end: 1.05,
   );
   }

心跳是不间断的,所以需要监听动画完成时恢复动画,再继续开始动画:

animation = Tween<double>(
     begin: 0.9,
     end: 1.05,
   ).animate(animController)
     ..addListener(() {
       setState(() {});
     })
     ..addStatusListener((status) {
       if (status == AnimationStatus.completed) {
         animController.reverse();
       } else if (status == AnimationStatus.dismissed) {
         animController.forward();
       }
     });

使用缩放控件:

Transform.scale(
               scale: animation.value,
               child: const FlutterLogo(
                 size: 80,
               ),
             ),

Flutter实现心动的动画特效

为了跳动效果,突出跳动动画,把缩回去的时间改短:

animController = AnimationController(
     reverseDuration: const Duration(milliseconds: 700),
     duration: const Duration(milliseconds: 800),
     vsync: this,
   );

最后别忘了释放资源:

@override
 void dispose() {
   animController.dispose();
   super.dispose();
 }

抽离成小组件

为了每次用到类似的动画只需引入即可,需要分离动画和显示的组件。新建一个BounceWidget,包含动画,然后可以传入UI组件:

class BounceWidget extends StatefulWidget {
 final Widget child;

const BounceWidget({
   Key? key,
   required this.child,
 }) : super(key: key);

@override
 State<BounceWidget> createState() => _BounceWidgetState();
}

继续实现动画:

class _BounceWidgetState extends State<BounceWidget>
   with SingleTickerProviderStateMixin {
 late Animation<double> animation;
 late AnimationController animController;

@override
 void initState() {
   super.initState();
   animController = AnimationController(
     reverseDuration: const Duration(milliseconds: 700),
     duration: const Duration(milliseconds: 800),
     vsync: this,
   );
   animation = Tween<double>(
     begin: 0.9,
     end: 1.05,
   ).animate(animController)
     ..addListener(() {
       setState(() {});
     })
     ..addStatusListener((status) {
       if (status == AnimationStatus.completed) {
         animController.reverse();
       } else if (status == AnimationStatus.dismissed) {
         animController.forward();
       }
     });
   animController.forward();
 }

@override
 Widget build(BuildContext context) {
   return Transform.scale(
     scale: animation.value,
     child: widget.child,
   );
 }

@override
 void dispose() {
   animController.dispose();
   super.dispose();
 }
}

去引入动画:

Center(
             child: BounceWidget(
               child: FlutterLogo(
                 size: 80,
               ),
             ),

完整代码

void main() {
 runApp(const MyApp());
}

class MyApp extends StatelessWidget {
 const MyApp({Key? key}) : super(key: key);

@override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
       primarySwatch: Colors.blue,
     ),
     home: const MyHomePage(title: 'Flutter Demo Home Page'),
   );
 }
}

class MyHomePage extends StatefulWidget {
 const MyHomePage({Key? key, required this.title}) : super(key: key);

final String title;

@override
 State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text(widget.title),
     ),
     body: Padding(
       padding: const EdgeInsets.only(top: 80, left: 16),
       child: Column(
         crossAxisAlignment: CrossAxisAlignment.start,
         children: const <Widget>[
           Text(
             "心动的",
             style: TextStyle(
               fontSize: 28,
               color: Colors.black,
             ),
           ),
           Text(
             "感觉",
             style: TextStyle(
               fontSize: 48,
               color: Colors.black,
             ),
           ),
           Center(
             child: BounceWidget(
               child: FlutterLogo(
                 size: 80,
               ),
             ),
           ),
         ],
       ),
     ),
   );
 }
}

来源:https://juejin.cn/post/7083418319159722020

标签:Flutter,动画,特效
0
投稿

猜你喜欢

  • java虚拟机钩子关闭函数addShutdownHook的操作

    2021-10-18 00:58:25
  • C# 实现颜色渐变窗体控件详细讲解

    2021-12-31 07:10:28
  • C#手动操作DataGridView使用各种数据源填充表格实例

    2023-07-20 08:30:31
  • 散列表的原理与Java实现方法详解

    2023-06-06 06:46:29
  • mybatis中<if>标签bool值类型为false判断方法

    2023-11-20 11:28:33
  • 使用jsoup解析html的table中的文本信息实例

    2021-06-19 23:07:59
  • C#实现获取机器码的示例详解

    2021-11-13 06:57:19
  • c#和java base64不一致的解决方法

    2022-11-24 02:18:55
  • Kotlin Option与Either及Result实现异常处理详解

    2022-03-31 17:33:18
  • java 查找替换pdf中的指定文本

    2022-08-17 14:04:46
  • 一文带你学会规则引擎Drools的应用

    2022-04-03 08:40:59
  • Spring Boot Hello World的实现代码

    2023-10-13 17:45:01
  • Java.try catch finally 的执行顺序说明

    2022-07-06 00:30:25
  • Java中的阻塞队列详细介绍

    2023-12-14 15:00:49
  • Spring boot配置 swagger的示例代码

    2023-03-07 13:10:44
  • Kotlin示例讲解标准函数with与run和apply的使用

    2023-06-12 15:47:11
  • java8 forEach结合Lambda表达式遍历 List操作

    2021-07-04 07:22:55
  • C# 获取 PC 序列号的方法示例

    2022-11-19 01:40:57
  • Java 数组获取最大和最小值的实例实现

    2021-06-18 15:53:06
  • 带你用C语言实现strtok和字符串分割函数

    2021-11-07 10:09:59
  • asp之家 软件编程 m.aspxhome.com