Flutter 動畫入門

超神的蘿菠發表於1970-01-01

官方動畫介紹

Widget動起來

1.使用Animation

原理類似於Android的屬性動畫,和Widget分離,在一定時間內生成一系列的值,值可以是int,double,color或者string等等,每隔N毫秒,或者N秒鐘獲取到最新的值去替換掉Widget上的值,同時重新整理佈局,如果重新整理間隔足夠小就能起到動畫的作用,例如構造一個Widget,他的width,height由動畫來控制,一定時間動態更新值使Widget產生動效:

new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,     
        width: animation.value,
        child: new FlutterLogo(),
      ),
複製程式碼

接下來看下如何使用Animation構建一個動態更新Widget的簡單場景

  • 匯入Animationimport 'package:flutter/animation.dart';
  • 建立StatefulWidget,建立Animation的實現類AnimationController,來構造一個最簡單的屬性動畫,並且應用到Widget上。
class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1000));
    animationController.addListener(() {
      setState(() {});
    });
    animationController.forward(); //啟動動畫
  }

  @override
  Widget build(BuildContext context) {
    print('tag' + animationController.value.toString());
    return Center(
      child: Container(
        width: animationController.value,
        height: animationController.value * 100,
        color: Colors.red,
      ),
    );
  }
}
複製程式碼

可以看到回撥列印的是從0-1的值,要返回其他型別的數值就需要用到TweenTween有許多子類例如:

image.png
來幫助我們實現更多的效果,使用Tween來實現從0-100的數值變換

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1000));
    animation = Tween(begin: 0.0,end: 100.0).animate(animationController);
    animationController.addListener(() {
      setState(() {});
    });
    animationController.forward(); //啟動動畫

  }

  @override
  Widget build(BuildContext context) {
    print('tag' + animationController.value.toString());
    return Center(
      child: Container(
        width: animation.value.toDouble(),
        height: animation.value.toDouble() ,
        color: Colors.red,
      ),
    );
  }
}
複製程式碼
2.使用AnimatedWidget來簡化程式碼AnimatedWidget,省去了addListener()以及setState()交給AnimatedWidget處理,感覺也沒省掉很多。。
class TestContainer extends AnimatedWidget {
  TestContainer({Key key,Animation animation})
      : super(key: key, listenable: animation);
 @override
  Widget build(BuildContext context) {
    // TODO: implement build
   Animation animation = listenable;
    return    Center(
      child: Container(
        width: animation.value.toDouble(),
        height: animation.value.toDouble() ,
        color: Colors.red,
      ),
    );
  }
}

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1000));
    animation = Tween(begin: 0.0,end: 100.0).animate(animationController);
    animationController.forward(); //啟動動畫
  }

  @override
  Widget build(BuildContext context) {
    return TestContainer(animation: animation,);
  }
}
複製程式碼
3.使用AnimatedWidget相關Api來再次簡化程式碼,例如使用RotationTransitionWidget在3秒鐘內旋轉360度

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(seconds: 10));
    animation = Tween(begin: 0.0, end: 1).animate(animationController);
    animationController.forward(); //啟動動畫
  }

  @override
  Widget build(BuildContext context) {
    return RotationTransition(turns: animation,
      child: Center(
          child: Container(color: Colors.red, width: 100, height: 100,)),);
  }
}
複製程式碼
4.對動畫過程進行監聽
animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        controller.forward();
      }
    });
複製程式碼
5.使用AnimationBuilder,將控制元件和動畫的控制過程進行封裝
class TestTransition extends StatelessWidget {
  TestTransition({this.child, this.animation});

  final Widget child;
  final Animation<double> animation;

  Widget build(BuildContext context) {
    return new Center(
      child: new AnimatedBuilder(
          animation: animation,
          builder: (BuildContext context, Widget child) {
            return new Container(
                height: animation.value, width: animation.value, child: child);
          },
          child: child),
    );
  }
}

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController =
        AnimationController(vsync: this, duration: Duration(seconds: 10));
    animation = Tween(begin: 0.0, end: 100.0).animate(animationController);
    animationController.forward(); //啟動動畫
  }

  @override
  Widget build(BuildContext context) {
    return TestTransition(
      child: Center(
          child: Container(
        color: Colors.red,
      )),
      animation: animation,
    );
  }
}
複製程式碼

相關文章