Flutter 之 动画2

在为 Widget 添加动画效果的过程中我们不难发现,Animation 仅提供动画的数据,因此我们还需要监听动画执行进度,并在回调中使用 setState 强制刷新界面才能看到动画效果。考虑到这些步骤都是固定的,Flutter 提供了两个类来帮我们简化这一步骤,即 AnimatedWidget 与 AnimatedBuilder。

AnimatedWidget

class WidgetAnimateWidget extends StatefulWidget {

@override

  StatecreateState()=>_WidgetAnimateWidgetState();

}

class _WidgetAnimateWidgetState extends Statewith SingleTickerProviderStateMixin {

AnimationController?controller;

late Animation animation;

@override

  void initState() {

super.initState();

// 创建动画周期为1秒的AnimationController对象

    controller =AnimationController(

vsync:this, duration:const Duration(milliseconds:3000));

final CurvedAnimation curve =CurvedAnimation(

parent:controller!, curve:Curves.easeIn);

// 创建从50到200线性变化的Animation对象

    animation =Tween(begin:10.0, end:200.0).animate(curve);

// 启动动画

    controller!.repeat(reverse:true);

}

@override

  Widget build(BuildContext context) {

return MaterialApp(

home:Scaffold(

body:AnimatedLogo(animation:animation,)

));

}

@override

  void dispose() {

// 释放资源

    controller!.dispose();

super.dispose();

}

}

class AnimatedLogo extends AnimatedWidget {

AnimatedLogo({Key? key,required Animation animation})

:super(key: key, listenable: animation);

Widget build(BuildContext context) {

Animation animation =listenable as Animation;

return Center(

child:Container(

height:animation.value,

width:animation.value,

child:FlutterLogo(),

),

);

}

}

在 AnimatedLogo 的 build 方法中,我们使用 Animation 的 value 作为 logo 的宽和高。这样做对于简单组件的动画没有任何问题,但如果动画的组件比较复杂,一个更好的解决方案是,将动画和渲染职责分离:logo 作为外部参数传入,只做显示;而尺寸的变化动画则由另一个类去管理。这个分离工作,我们可以借助 AnimatedBuilder 来完成。与 AnimatedWidget 类似,AnimatedBuilder 也会自动监听 Animation 对象的变化,并根据需要将该控件树标记为 dirty 以自动刷新 UI。

class BuilderAnimateWidget extends StatefulWidget {

@override

  StatecreateState() {

return _BuilderAnimateState();

}

}

class _BuilderAnimateState extends Statewith SingleTickerProviderStateMixin {

late AnimationController controller;

late Animationanimation;

@override

  void initState() {

super.initState();

// 创建动画周期为1秒的AnimationController对象

    controller =AnimationController(

vsync:this, duration:const Duration(milliseconds:3000));

final CurvedAnimation curve =CurvedAnimation(

parent:controller, curve:Curves.easeInOut);

// 创建从50到200线性变化的Animation对象

    animation =Tween(begin:10.0, end:200.0).animate(curve);

// 启动动画

    controller.repeat(reverse:true);

}

@override

  Widget build(BuildContext context) {

return MaterialApp(

home:Scaffold(

body:Center(

child:AnimatedBuilder(

animation:animation,

//child:FlutterLogo(),

                    builder: (context, child) =>Container(

width:animation.value,

height:animation.value,

child:FlutterLogo(),

)

)

)

));

}

@override

  void dispose() {

// 释放资源

    controller.dispose();

super.dispose();

}

}

hero 动画

通过 Hero,我们可以在两个页面的共享元素之间,做出流畅的页面切换效果。

为了实现共享元素变换,我们需要将这两个组件分别用 Hero 包裹,并同时为它们设置相同的 tag “hero”。


class Page2 extends StatelessWidget {

Widget build(BuildContext context) {

return  Scaffold(

appBar:AppBar(title:Text('Page1'),),

body:GestureDetector(

child:Row(children: [

Hero(

tag:'hero',// 设置共享 tag

                child:Container(

width:100, height:100,

child:FlutterLogo())

),

Text('点击Logo查看Hero效果')

],),

onTap: () {

Navigator.of(context).push(MaterialPageRoute(builder: (_)=>Page2()));

},

)

);

}

}

class Page2 extends StatelessWidget {

@override

  Widget build(BuildContext context) {

return  Scaffold(

appBar:AppBar(title:Text('Page2'),),

body:Hero(

tag:'hero',// 设置共享 tag

            child:Container(

width:300, height:300,

child:FlutterLogo()

))

);

}

}

你可能感兴趣的:(Flutter 之 动画2)