Flutter 奇思妙想- 按压动画(一)

551 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情

前几天和一个朋友沟通中,知道他在学习flutter.他问了我一个问题.让我陷入了沉思.TT,我现在学习flutter.我应该从何入手呢.看似很简单的问题.其实这个如何入手真的很重要.基于这个问题.后续我也会出一个系列.专门针对初学者.从入门到项目做详细的讲解.

引言

前段时间做了小程序简答动画.我这么爱折腾的人.怎么会放过flutter呢.刚好今天看到了App StroeToday点击动画.觉得很有意思,那就把它实现吧

您会在这里看到啥

  1. 实现效果
  2. 动画分析
  3. 实现动画

实现效果

MTVideo.GIF

动画分析

从上面的展示效果中,我们最直观的就是,当点击item的时候,会有一个缩放的效果. 并在缩放动画结束的时候,做了界面跳转.并使用hero动画.下面来仔细的分析一下.

  • 缩放动画
    1. 按下动画
    2. 弹起动画
  • 跳转动画
    1. 路由动画
    2. Hero动画

实现缩放动画

经过上面的分析.也就缩放动画是需要我们自己实现的.跳转动画暂时可以使用系统提供的Hero即可完成.下面我们一起来实现一下按压缩放动画即可.

  1. 查看缩放效果

    MTVideo 3.GIF

  2. 选用合适的组件

    • 从手势上分析.我们选用GestureDetector

      经过查看源码,可以知道GestureDetector的按压事件回调

      截屏2022-12-19 22.11.52.png 整个按压事件的周期如下所示 截屏2022-12-19 22.23.00.png

      完全满足我们的需求,剩下的只需要在对应的事件中,做缩小放大即可.

    • 从缩放动画效果上来说,有两个实现方式

      1. size + AnimationController(不可取这里就不举例说明了)
      2. Transform.scale + AnimationController(已实现)
      3. Tween + AnimationController(还未实现,后续添加上)
  3. 实现缩放动画

    1. 确认缩放范围

      经过简单的分析,我们这里就就设置缩放范围为0.9 ~ 1.0.

    2. 确认item层级

      截屏2022-12-19 22.39.36.png

      经过图层分析,我们来看一下代码是怎么实现的

      截屏2022-12-19 22.40.40.png

      如上所示,满足了我们缩放动画的需求,然后你会惊奇的发现.这里的scale的值是怎么改变的.单纯的在点击事件里直接改变scale值.如下所示

      _ontapDown() {
        setState(() {
            scale = 0.9;
        });
      }
      
      _onTapUp() {
        setState(() {
            scale = 1;
        });
      }
      

      上面不是不可以完成动画, 只是略显粗糙.你会感觉不丝滑.少点什么.

      既然要做的是动画,这样直接改变大小,完全没得灵魂.必须注入灵魂.这样AnimationController就必须站起来了

    3. 优雅的控制scale.

      • AnimationController

        • 含义

          动画控制器.它可以控制动画的启动(forward)、暂停(stop)、回滚(reverse)、以及反复(repeat).还有最重要的动画事件监听.

          这里我们就简单的提一下AnimationController是啥.具体使用,后续文章,会针对动画出一个系列.

        • 使用

          1. 创建控制器
            • 继承协议

              with SingleTickerProviderStateMixin 
              
            • 创建控制器

                _controller = AnimationController(
                  vsync: this,
                  duration: const Duration(milliseconds: 200),
                  lowerBound: 0.0,
                  upperBound: 0.1)
              

              参数说明

              注意:这里只说使用的

              参数含义
              duration动画执行时间
              lowerBound动画最小边界值
              upperBound动画最大边界值

              由于我们这里使用方式是改变Transform.scale的值,来实现缩放效果的.所以这个动画的范围有两种配置

              1. lowerBuoud: 0.0, upperBound: 0.1 这种方式scale的取值如下所示
                 scale = 1 - _controller!.value;
                
              2. lowerBuoud: 1.0,upperBound: 0.9 这种方式scale的取值如下所示
                scale = _controller!.value;
                
            • 监听控制器

               ..addListener(() {
                   // 监听动画变化
                   // 可以用于刷新scale值
                   setState(() {});
                })
                 ..addStatusListener((status) {
                   if (status == AnimationStatus.dismissed) {
                       // 这个监听,是监听动画的状态值的改变.
                       // 因为我们的跳转动画,是在动画执行完成的时候
                       // 在执行跳转逻辑, 如果不做状态监听,那么当手离开屏幕
                       // 时候,就直接跳转,会很突兀
                      
                    }
                 });
              
              
        1. 动画启动

          /// 只有在按下的时候,启动动画
            _controller!.forward();
          
        2. 动画回滚

          动画回滚有两个事件需要处理.一个就是手势回弹,一个就是触摸结束.因为在手势中,用户不可能只会点击item.也会滑动item,如果此时不做处理.那个当前item在手指离开屏幕的时候,不会做动画回滚效果,当然我这里写的有可能也不全,但逻辑都是一样的.

          _controller!.reverse();
          
          
        3. 给需要缩放的组件,配置缩放大小.

          我们的需求是,点那个,那个缩放.由于我们的动画刷新是全局的.如果不做处理,会发现,所有的item都一起执行缩放动画,所以我们需要在缩放时,判断当前item是不是我们点击的,如下所示

          Transform.scale(scale: index == tapindex ? scale : 1, child: child);
          

      经过上面的编写,我们就基本上完成,缩放动画.后续我会把路由跳转动画,也一起分享一下.

DEMO