Flutter 動畫入門

官方動畫介紹bash

Widget動起來

1.使用Animation

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

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

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

  • 導入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,
    );
  }
}
複製代碼
相關文章
相關標籤/搜索