【无标题】flutter 动画入门

大家好,我是 17。
flutter 动画相关的有很多类。 一开始的时候不知道怎么用。本文通过示例,逐步展示相关的类的用法。

为了展示动画原理,我们从 AnimationController 类开始。

最简单的动画

import 'package:flutter/material.dart';

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

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

  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> with TickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    _controller =
        AnimationController(duration: const Duration(seconds: 1), vsync: this)
          ..repeat()
          ..addListener(() {
            setState(() {});
          });
    super.initState();
  }
  
  Widget build(BuildContext context) {
    return Center(child: Container(
      color: Colors.green,
      width: 100 * _controller.value,
      height: 50 * _controller.value,
    ));
  }
}

copy 上面的代码放到 main.dart里 执行,会看到一个不断放大的矩形。

_controller.value 的变化区间是 从 0 到 1。 如果想从 100,200变化呢?加一个 tween

class _AppState extends State<App> with TickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;
  
  void initState() {
    _controller =
        AnimationController(duration: const Duration(seconds: 1), vsync: this)
          ..repeat()
          ..addListener(() {
            setState(() {});
          });
    _animation = Tween<double>(begin: 1, end: 2).animate(_controller);
    //或这样写
    // _animation =_controller.drive(Tween<double>(begin: 1, end: 2));
    super.initState();
  }

  
  Widget build(BuildContext context) {
 
    return Center(
        child: Container(
      color: Colors.green,
      width: 100 * _animation.value,
      height: 50 * _animation.value,
    ));
  }
}

也许你会问,为什么加了一个_animation。 因为 tween 的 animate 方法会生成一个 新的 Animation对象。这样新的对象把原来的 [0,1] 区间映射成 tweeen 规定的区间 做数据输出。 新对象的职责是提供数据,原来的 _controller 对动画进行控制。

目前的数据的变化是线性的,想变成 ease 呢?加一个 curve即可

_animation = Tween<double>(begin: 1, end: 2)
        .chain(CurveTween(curve: Curves.ease))
        .animate(_controller);

这样写也是可以的

 _animation = _controller
        .drive(Tween<double>(begin: 1, end: 2))
        .drive(CurveTween(curve: Curves.ease));

至此,动画的精华就介绍完了。

动画性能

上面的示例中用的是整页刷新,为了能局部刷新 flutter 提供了两个组件

AnimatedWidget

它的作用就是把 setState 方法封装了起来,我们不用手动调用,而且把刷新限制在了 AnimatedWidget之内。下面用 AnimatedWidget 把开始的示例改造一下。

import 'package:flutter/material.dart';

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

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

  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> with TickerProviderStateMixin {
  late AnimationController _controller;

  
  void initState() {
    _controller =
        AnimationController(duration: const Duration(seconds: 1), vsync: this)
          ..repeat();

    super.initState();
  }

  
  Widget build(BuildContext context) {
    return Center(
        child: MyWidget(
      animation: _controller,
    ));
  }
}

class MyWidget extends AnimatedWidget {
  const MyWidget({Key? key, required this.animation})
      : super(key: key, listenable: animation);
  final Animation<double> animation;
  
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      width: 100 * animation.value,
      height: 50 * animation.value,
    );
  }
}

用 AnimatedWidget 就不需要再手动 setState了。但每次都需要把动画 包装成一个widget。

AnimatedBuilder

不需要把动画部分包装成 Widget。只把 build函数修改下即可。

 Widget build(BuildContext context) {
   return Center(
       child: AnimatedBuilder(
     animation: _controller,
     builder: (context, _) {
       return Container(
         color: Colors.green,
         width: 100 * _controller.value,
         height: 50 * _controller.value,
       );
     },
   ));
 }

本例中的 container没有child ,所以不会有性能问题,但是如果 container有一个复杂的child,每次都重建,这个成本还是很高的。需要优化一下

 Widget build(BuildContext context) {
  var child = Container(
    color: Colors.lightBlue,
  );
  return Center(
      child: AnimatedBuilder(
    animation: _controller,
    child: child,
    builder: (context, child) {
      return Container(
        color: Colors.green,
        width: 100 * _controller.value,
        height: 50 * _controller.value,
        child: child,
      );
    },
  ));
}
}

这里简单的用一个蓝色container做为 child,实际中可能 是一个 widget。用child参数的好处是提高性能,child 只 build 一次。

CustomPainter

对于性能要求较高的场合,可以用 CustomPainter 提高性能。

import 'package:flutter/material.dart';

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

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

  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> with TickerProviderStateMixin {
  late AnimationController _controller;

  
  void initState() {
    _controller =
        AnimationController(duration: const Duration(seconds: 1), vsync: this)
          ..repeat();

    super.initState();
  }

  
  Widget build(BuildContext context) {
    return Center(
        child: CustomPaint(
      painter: MyPainter(animation: _controller),
      size: const Size(100, 50),
    ));
  }
}

class MyPainter extends CustomPainter {
  final Animation<double> animation;
  MyPainter({required this.animation}) : super(repaint: animation);
  
  void paint(Canvas canvas, Size size) {
    var rect =
        Rect.fromLTWH(0, 0, 100 * animation.value, 100 * animation.value);
    canvas.drawRect(
        rect,
        Paint()
          ..style = PaintingStyle.fill
          ..color = Colors.green);
  }

  
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

关键代码就一句 super(repaint: animation); repaint 是一个 Listenable 对象。只要有变化,就会执行重绘,与 shouldRepaint 返回值无关。

从绘制上下手,无需再 build 任何 widget,坏处是需要自己调用 canvas 绘制,成本较高。

至此,动画的核心知识就讲完了。剩下的都是锦上添花的东西了。剩下的都不知道也没有关系,知道了会方便与别人沟通。

显式动画

显式动画是指需要提供动画控制器的类

AnimatedWidget 扩展类

这些类知道名字就好,对于不好理解的我都加了链接,可以看文档,上面有动画效果或说明。

AnimatedBuilder 也是继承自 AnimatedWidget。

其它类

FadeTransition 它不是继承自 AnimatedWidget ,通过动画控制器来控制透明度。

  final Animation<double> opacity;

与之相关的是 AnimatedOpacity,和 FadeTransition 功能一样,只是不需要动画控制器。用 double数值控制透明度

 final double opacity;

隐式动画

隐式动画是指不需要提供动画控制器的类,改变属性就可以触发动画。 包括

  • AnimatedPadding
  • AnimatedAlign
  • AnimatedTheme
  • TweenAnimationBuilder
  • AnimatedPositionedDirectional
  • AnimatedPositioned
  • SliverAnimatedOpacity
  • AnimatedContainer
  • AnimatedPhysicalModel
  • AnimatedDefaultTextStyle
  • AnimatedOpacity

。一般是以 Animated 开头。

到这就差不多了,还有一些动画组件,也可以归为显示动画或隐式动画之列。

本文的目的,是为了让你对动画有一个轮廓级别的认识。知道类的作用,怎么把它们关联起来, 细节可以去查文档或看源码。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IAM17前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值