写点什么

Flutter 使用 AnimatedSwitcher 做场景切换

作者:岛上码农
  • 2022 年 7 月 17 日
  • 本文字数:2156 字

    阅读完需:约 7 分钟

Flutter 使用 AnimatedSwitcher 做场景切换

前言

在应用中,我们经常会遇到切换组件的场景,比如点击一个按钮后,将当前的图片为另一张图片;或者是翻转卡片,显示卡片详情。在 Flutter 中提供了 AnimatedSwitcher 这个动画组件来实现页面内的场景切换。


AnimatedSwitcher 介绍

AnimatedSwitcher 通过动效完成其子组件的切换,默认的效果是 FadeTransition。当其子组件发生改变的时候,就会按设定的转变效果进行转换。AnimatedSwitcher的构造方法如下:


const AnimatedSwitcher({  Key? key,  this.child,  required this.duration,  this.reverseDuration,  this.switchInCurve = Curves.linear,  this.switchOutCurve = Curves.linear,  this.transitionBuilder = AnimatedSwitcher.defaultTransitionBuilder,  this.layoutBuilder = AnimatedSwitcher.defaultLayoutBuilder,})
复制代码


与之前其他的动画组件不同,AnimatedSwitcher的参数除了 duration 之外,其他的有所不同,具体如下:


  • reverseDuration:反向时长,也就是切换为旧组件的时长,不设置的话就和 duration 一致。

  • switchInCurve:切入动画曲线,也就是新组件切换进入的曲线;

  • switchOutCurve:切出动画曲线,也就是旧组件切换出去时的曲线;

  • transitionBuilder:切换转变动画构建,是一个函数,定义如下,可以用这个方法来构建自己的切换动效。


typedef AnimatedSwitcherTransitionBuilder = Widget Function(Widget child, Animation<double> animation);
复制代码


  • layoutBuilder:可以设置新组件在组件树中的布局,也是一个函数:


typedef AnimatedSwitcherLayoutBuilder = Widget Function(Widget? currentChild, List<Widget> previousChildren);
复制代码


默认布局为 defaultLayoutBuilder,也就是将当前组件放置在最顶层:


static Widget defaultLayoutBuilder(Widget? currentChild, List<Widget> previousChildren) {  return Stack(    children: <Widget>[      ...previousChildren,      if (currentChild != null) currentChild,    ],    alignment: Alignment.center,  );}
复制代码


关于AnimatedSwitcher有一个地方需要特别注意,那就是如果切换的两个组件相同的话,AnimatedSwitcher会以为组件没有改变,而不会进行动效切换。文档说明如下:


The child is considered to be "new" if it has a different type or [Key]


实际上是根据 WidgetcanUpdate 判断的:


static int _debugConcreteSubtype(Widget widget) {  return widget is StatefulWidget ? 1 :         widget is StatelessWidget ? 2 :         0;}
复制代码


因此,如果两个组件类型相同,需要使用不同的 Key 来区分,通常是使用 ValueKey

应用

下面我们来实现开篇的动效,这个使用的是 SizeTransition 尺寸变化转变动效完成两张图片的切换,这样会让组件的尺寸从小变到大,有一种掀开面纱的感觉。代码如下:


class AnimatedSwitcherDemo extends StatefulWidget {  AnimatedSwitcherDemo({Key? key}) : super(key: key);
@override _AnimatedSwitcherDemoState createState() => _AnimatedSwitcherDemoState();}
class _AnimatedSwitcherDemoState extends State<AnimatedSwitcherDemo> { Widget? _animatedWidget; bool test = false;
@override void initState() { super.initState(); _animatedWidget = ClipOval( child: Image.asset('images/beauty.jpeg'), key: ValueKey(1), ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('AnimatedSwticher'), brightness: Brightness.dark, backgroundColor: Colors.black, ), backgroundColor: Colors.black, body: Center( child: Container( padding: EdgeInsets.all(10.0), child: AnimatedSwitcher( child: _animatedWidget, duration: const Duration(milliseconds: 1000), transitionBuilder: (child, animation) { return SizeTransition( sizeFactor: animation, child: child, ); }, ), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.play_arrow), onPressed: () { setState(() { test = !test; _animatedWidget = test ? ClipOval( child: Image.asset('images/beauty2.jpeg'), key: ValueKey(2), ) : ClipOval( child: Image.asset('images/beauty.jpeg'), key: ValueKey(1), ); }); }, ), ); }}
复制代码

总结

本篇介绍了 AnimatedSwitcher 动画组件的使用。AnimatedSwitcher可以用于界面中组件的切换过渡动效,并且可以控制切入切出的时长、动画取消、过渡效果和布局,从而可以实现一些有趣的切换效果。另外,需要注意的是,如果要切换的子组件类型相同,则需要使用 Key 进行区分,否则动效不会呈现出来。


发布于: 刚刚阅读数: 4
用户头像

岛上码农

关注

用代码连接孤岛,公众号@岛上码农 2022.03.03 加入

从南漂到北,从北漂到南的业余码农

评论

发布
暂无评论
Flutter 使用 AnimatedSwitcher 做场景切换_flutter_岛上码农_InfoQ写作社区