flutter 動畫初探(繪製動畫)

今天開始學習flutter中動畫的使用,什麼叫繪製動畫呢,其實我想表達的意思是,結合上一篇文章中學習的繪製,本文中讓它動起來😁

準備着手做一個類似於加載圈的動畫,比如說下拉刷新,或者頁面網絡請求加載時的動畫,這篇文章先做一個建議版的,來個動畫入門😋

先對flutter中的動畫做個簡單介紹:

Flutter的動畫也不復雜,關鍵詞AnimationController

Flutter中的動畫是基於Animation,這個對象本身是一個抽象類,在一段時間內依次產生一些值。我們使用封裝好的AnimationController來做動畫,它在屏幕刷新的每一幀,產生一個新的值,默認情況是在給定的時間段內線性的生成0.0到1.0的數字。

需要注意的是在使用AnimationController的時候需要結合TickerProvider,因爲只有在TickerProvider下才能配置AnimationController中的構造參數vsyncTickerProvider是一個抽象類,所以我們一般使用它的實現類TickerProviderStateMixinSingleTickerProviderStateMixin

那麼,這兩種方式有什麼不同呢? 如果整個生命週期中,只有一個AnimationController,那麼就使用SingleTickerProviderStateMixin,因爲此種情況下,它的效率相對來說要高很多。反之,如果有多個AnimationController,就是用TickerProviderStateMixin

還有duration屬性可以設置持續時間。還有一些方法可以控制動畫forward啓動,reverse反轉,repeat重複。

AnimationControlleraddListeneraddStatusListener方法可以添加監聽,一個是值監聽一個是狀態監聽。值監聽常用在調用setState來觸發UI重建來實現動畫,狀態監聽用在動畫狀態變化的時候執行一些方法,比如在動畫結束時反轉動畫。

簡單瞭解完上述的這些屬性和方法之後,就可以做一個簡單地動畫來練練手了

這裏的需求是一段圓弧在給定的圓形路徑上不斷轉圈,在點擊click之後,整個圓形路徑填充一圈,然後結束

這裏我們先進行繪製,順便複習一下上一篇文章裏面學到的內容:

class MyPainter extends CustomPainter {
  Color lineColor;
  Color completeColor;
  double startPercent;//圓弧轉動時 開始的位置
  bool isComplete = false;
  double width;

  MyPainter(
      {this.lineColor,
      this.completeColor,
      this.startPercent,
      this.width,
      this.isComplete : false});
  @override
  void paint(Canvas canvas, Size size) {
    Paint line = Paint()
      ..color = lineColor
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = width;

    Paint complete = Paint()
      ..color = completeColor
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = width;

    Offset center = Offset(size.width / 2, size.height / 2); //  座標中心
    double radius = min(size.width / 2, size.height / 2); //  半徑
    canvas.drawCircle(
    //  畫圓方法
        center,
        radius,
        line);

    double arcAngle = isComplete == true ? startPercent : 2 * pi / 10;

    //畫轉動的圓弧
    canvas.drawArc(Rect.fromCircle(center: center, radius: radius),
        isComplete == true ? 2 * pi  : startPercent, arcAngle, false, complete);
  }

  @override
  bool shouldRepaint(MyPainter oldDelegate) {
    return startPercent != oldDelegate.startPercent;
  }
}

所謂動畫,大概就是動起來的畫吧,現在畫已經有了,下一步就是讓他動起來

class _HomeContentState extends State<HomeContent>
    with TickerProviderStateMixin {
  double percentage = 0.0;
  AnimationController percentageAnimationController;
  bool isClick = false;

  @override
  void initState() {
    super.initState();
    percentageAnimationController = new AnimationController(
        vsync: this, duration: new Duration(milliseconds: 2000))
      ..repeat()
      ..addListener(() {
        setState(() {
          percentage = percentageAnimationController.value * pi * 2;
        });
      });
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        height: 200.0,
        width: 200.0,
        child: new CustomPaint(
          foregroundPainter: new MyPainter(
              lineColor: Colors.lightBlueAccent,
              completeColor: Colors.blueAccent,
              startPercent: percentage,
              isComplete: isClick,
              width: 8.0),
          child: new Padding(
            padding: const EdgeInsets.all(8.0),
            child: new RaisedButton(
                color: Colors.green,
                splashColor: Colors.transparent,
                shape: new CircleBorder(),
                child: new Text("Click"),
                onPressed: () {
                  setState(() {
                    isClick = true;

                    percentageAnimationController.forward(from: 0.0);
                  });
                 
                }),
          ),
        ),
      ),
    );
  }
}

就是上面介紹動畫裏面的步驟,就不再重複了,當然也可以換一種寫法用AnimatedBuilder,就不需要setState了

Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        height: 200.0,
        width: 200.0,
        child: AnimatedBuilder(animation: percentageAnimationController, builder: (context, child) {
          return new CustomPaint(
          foregroundPainter: new MyPainter(
              lineColor: Colors.lightBlueAccent,
              completeColor: Colors.blueAccent,
              startPercent: percentage,
              isComplete: isClick,
              width: 8.0),
          child: new Padding(
            padding: const EdgeInsets.all(8.0),
            child: new RaisedButton(
                color: Colors.green,
                splashColor: Colors.transparent,
                shape: new CircleBorder(),
                child: new Text("Click"),
                onPressed: () {
                    isClick = true;
                    percentageAnimationController.forward(from: 0.0);
                 
                }),
          ),
        );
        })
        
      ),
    );
  }

有一點需要注意的是,controller的銷燬

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章