Flutter 记录学习不一样的动画(二)

一、AnimatedWidget 简介

AnimatedWidget 基本类可以从动画代码中区分出核心 widget 代码。 AnimatedWidget 不需要保持 State 对象来 hold 动画。AnimatedWidget 帮助类(代替 addListener() 和 setState())创建动画 widget。
利用 AnimatedWidget 创建一个可以运行重复使用动画的 widget。
Flutter API 中的 AnimatedWidget:AnimatedBuilder, RotationTransition, ScaleTransition, SizeTransition, SlideTransition。

二、AnimatedWidget 动画示例

一个从矩形的宽高收缩

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

  @override
  _MyAnimationWidgetState createState() => _MyAnimationWidgetState();
}

class _MyAnimationWidgetState extends State<MyAnimationWidget>
    with SingleTickerProviderStateMixin {
    
    
  late AnimationController controller;
  late Animation<double> animation;

  @override
  initState() {
    
    
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = Tween(begin: 0.0, end: 300.0).animate(controller);
    controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      body: Center(
        child: AnimationLogo(animation),
      ),
    );
  }
}

class AnimationLogo extends AnimatedWidget {
    
    
 const AnimatedLogo({
    
    super.key, required Animation<double> animation})
      : super(listenable: animation);

  @override
  Widget build(BuildContext context) {
    
    
   final animation = listenable as Animation<double>;
    return Center(
      child: Container(
        height: animation.value,
        width: animation.value,
        color: Colors.red,
      ),
    );
  }
}

三、使用 AnimatedBuilder 进行重构

AnimatedBuilder 知道如何渲染过渡效果

但 AnimatedBuilder 不会渲染 widget,也不会控制动画对象。

使用 AnimatedBuilder 描述一个动画是其他 widget 构建方法的一部分。如果只是单纯需要用可重复使用的动画定义一个 widget。

Flutter API 中 AnimatedBuilders:BottomSheet, ExpansionTile, PopupMenu, ProgressIndicator, RefreshIndicator, Scaffold, SnackBar, TabBar, TextField。

AnimatedWidget 示例代码中有个问题,就是改变动画需要改变渲染 logo 的widget。较好的解决办法是,将任务区分到不同类里:

a. 渲染 logo

b. 定义动画对象

c. 渲染过渡效果

AnimatedBuilder 动画示例

class _MyAnimationWidgetState extends State<MyAnimationWidget>
    with SingleTickerProviderStateMixin {
    
    
  late AnimationController controller;
  late Animation<double> animation;

  @override
  initState() {
    
    
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = Tween(begin: 0.0, end: 300.0).animate(controller);
    controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      body: Center(
        child: AnimationLogo(
          animation,
          child: LogoWidget(),
        ),
      ),
    );
  }
}

class LogoWidget extends StatelessWidget {
    
    
  const LogoWidget({
    
    Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    
    
    return Center(
      child: Container(
        color: Colors.red,
      ),
    );
  }
}

class AnimationLogo extends StatelessWidget {
    
    
  final Animation<double> animation;
  final Widget child;
  AnimationLogo(this.animation, {
    
    Key? key, required this.child});

  @override
  Widget build(BuildContext context) {
    
    
    return AnimatedBuilder(
      animation: animation,
      builder: (BuildContext context, Widget? child) {
    
    
        return SizedBox(
          height: animation.value,
          width: animation.value,
          child: child,
        );
      },
      child: child,
    );
  }
}

四、总结

从上面代码可以看出widget和动画效果分开了,所以AnimatedBuilder进一步将AnimatedWidget 进行分离,这样就可以让动画效果进行复用了,非常不错的。

猜你喜欢

转载自blog.csdn.net/hjjdehao/article/details/126059714