FLUTTER学习笔记--动画


一、动画

1.补间(Tween)动画

  • 在补间动画中我们定义开始点和结束点、时间线以及定义转换时间和速度曲线。然后由系统计算,从开始点到结束点。从而形成动画效果
  • 例如:透明度从0到1,颜色值从0到255

2.拟物动画

  • 拟物动画是对真实世界的行为进行建模,使动画效果类似于现实中的物理效果
  • 例如:弹簧,阻尼,重力,抛物线等

3.Animation

  • Animation是Flutter动画库中的一个核心类。它包含动画的值和状态两个属性,定义了动画的一系列监听函数
    • 监听值
      • addListener
      • removeListener
    • 监听状态
      • addStatusListener
      • removeStatusListener
  • 动画状态
    • AnimationStatus.dismissed(动画初始状态)

    • AnimationStatus.completed(动画结束状态)

    • AnimationStatus.forward(动画处在从开始到结束的运行状态)

    • AnimationStatus.reverse(动画处在从结束到开始的运行状态)

  • 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到0.1,如果希望使用不同的区间,或不同的数据类型,需要使用Tween

    • Tween的唯一职责就是定义从输入范围到输出范围的映射

    • Tween(begin,end)

    • ColorTween(begin:Colors.颜色,end:Colors.颜色)

  • CurvedAnimation
    • 简介
      • 动画执行的速度有多种(匀速、先快后慢或先慢后快)这里的速度称为动画曲线
      • CurvedAnimation的目的是为AnimationController添加动画曲线
    • 组件
      • CurvedAnimation(parent:controller,curve:Curves.easeIn)
        • parent(动画控制器对象)

        • curve(正向执行的动画曲线)

        • reverseCurve(反向执行的动画曲线)

      • Curves

4.步骤

  • 创建动画控制器
    • controller = AnimationController(duration, vsync);
  • 创建动画
    • 动画曲线(CurvedAnimation)
    • 补间动画(Tween)
  • 监听动画
    • addListener()-监听动画生产值
    • addStatusListener()-监听动画状态
  • 执行动画
    • controller.forward()-正向执行
    • controller.reverse()-反向执行

5.代码

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: Duration(milliseconds: 400), vsync: this);

    //2.声明动画曲线
    animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn);

    //3.设置动画值的范围
    animation = Tween(begin: 50.0, end: 300.0).animate(controller);

    //4.监听动画
    animation.addListener(() {
      print(animation.value);
      setState(() {});
    });

    //5.执行动画
    //controller.forward();
  }

  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          ElevatedButton(
              onPressed: () {
                controller.forward();
              },
              child: Text('放大')),
          ElevatedButton(
              onPressed: () {
                controller.reverse();
              },
              child: Text('缩小')),
          ElevatedButton(
              onPressed: () {
                animation.addStatusListener((status) {
                  if (status == AnimationStatus.completed) {
                    //反向执行动画
                    controller.reverse();
                  } else if (status == AnimationStatus.dismissed) {
                    //正向
                    controller.forward();
                  }
                });
                controller.forward();
              },
              child: Text('重复')),
          ElevatedButton(
              onPressed: () {
                controller.stop();
              },
              child: Text('停止')),
          Icon(
            Icons.accessible_forward_outlined,
            color: Colors.blue,
            size: animation.value,
          ),
          Opacity(
            opacity: controller.value,
            child: Text('hello world'),
          )
        ],
      ),
    );
  }

  //切换至后台的时候会调用来释放资源
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    controller.dispose();
  }
}

6.效果

dbc35f39-63d7-453d-b2f8-6b60af1e7810.gif

二、交织动画

1.交织动画是由多个单元动画叠加而成复杂动画

2.需要给每个动画设置时间间隔(Interval)

3.Transform

  • 平移-Transform.translate()
  • 旋转-Transform.rotate()
  • 缩放-Transform.scale()

4.代码

class StaggerAnimationDemo extends StatefulWidget {
  const StaggerAnimationDemo({Key? key}) : super(key: key);

  @override
  State<StaggerAnimationDemo> createState() => _StaggerAnimationDemoState();
}

class _StaggerAnimationDemoState extends State<StaggerAnimationDemo>
    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(duration: Duration(seconds: 3), vsync: this);

    //2.创建动画
    animation = CurvedAnimation(parent: controller, curve: Interval(0.0, 0.5))
      ..addListener(() {});

    //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); //需要将animation设为<double>
    colorAnimation = ColorTween(begin: Colors.yellow, end: Colors.red).animate(
        CurvedAnimation(
            parent: controller,
            curve: Interval(0.5, 0.8, curve: Curves.bounceIn)))
      ..addListener(() {
        setState(() {});
      });
    rotationAnimation = Tween(begin: 0.0, end: 2 * pi).animate(CurvedAnimation(
      parent: controller,
      curve: Interval(0.8, 1.0, curve: Curves.easeIn),
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          ElevatedButton(
              onPressed: () {
                controller.forward();
              },
              child: Text('重复')),
          ElevatedButton(
              onPressed: () {
                controller.stop();
              },
              child: Text('停止')),
          Icon(
            Icons.accessible_forward_outlined,
            color: Colors.blue,
            size: animation.value,
          ),
          Opacity(
              opacity: controller.value,
              child: Transform.rotate(
                angle: rotationAnimation.value,
                child: Container(
                  width: sizeAnimation.value,
                  color: colorAnimation.value,
                  height: sizeAnimation.value,
                ),
              ))
        ],
      ),
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    controller.dispose();
  }
}

5.效果

a30eaa3d-dffe-43e9-a792-70c2af3bdf98.gif

三、Hero动画

1.Hero动画是拥有实现跨页面的动画效果

  • 在不同页面中,声明一个共享组件(Hero)
  • 由于共享组件在不同页面中的位置、外观等不同,路由切换时,形成动画效果

2.步骤

  • 在页面A中定义起始Hero组件(source hero),声明tag
  • 在页面A中定义目标Hero组件(destination hero),绑定相同的tag
  • 页面跳转时,通过Navigator,传递tag

3.Hero组件

  • tag(路由切换时,共享组件的标记)
  • child(声明子组件)

4.代码

class HeroAnimationDemo extends StatelessWidget {
  const HeroAnimationDemo({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(vertical: 50),
      child: GridView.extent(
          maxCrossAxisExtent: 300.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);
              }));
            },
            child: Hero(
              tag: imageURL,
              child: Image.network(imageURL),
            ),
        );
        }),
      ),
    );
  }
}

class ImageDetail extends StatelessWidget {
  final String imageURl;
  ImageDetail(this.imageURl);

  @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,
            ),
          ),
        ),
      ),
    );
  }
}

5.效果

a04443f0-888d-4c54-93e2-faed0990b1ce.gif

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值