Flutter動畫及示例

藍色微笑ing發表於2019-11-26

動畫型別

動畫型別:

  • 補間(Tween)動畫

    “介於兩者之間”的簡稱。在補間動畫中,定義了開始點和結束點、時間線以及定義轉換時間和速度的曲線。然後由框架計算如何從開始點過渡到結束點。

  • 基於物理的動畫

    在基於物理的動畫中,運動被模擬為與真實世界的行為相似。例如,當你擲球時,它在何處落地,取決於拋球速度有多快、球有多重、距離地面有多遠。 類似地,將連線在彈簧上的球落下(並彈起)與連線到繩子上的球放下的方式也是不同。

動畫常見表現形式

  • 動畫列表或網格
    • 在網格或列表中新增或刪除元素時應用動畫
  • 共享元素轉換(Hero)
    • 實現路由(頁面)之間的共享元素過渡動畫
  • 交錯動畫
    • 交錯動畫由一個動畫序列或重疊的動畫組成
    • 一個AnimationController控制所有動畫

動畫庫中的一些主要類

Animation

動畫系統的主要構件, 接收特定型別的值,該值可以在動畫的生命週期內更改。可以從該物件讀取動畫的當前值,並監聽該值的更改。

  • addListener(VoidCallback listener)

    監聽Animation的值發生改變,如果要取動畫當前的值,呼叫animation.value即可

  • addStatusListener(AnimationStatusListener listener)

    監聽動畫的狀態改變, AnimationStatus有四種狀態:dismissed、forward、reverse、completed

Animation<double> _animation = Tween(begin: 0.0, end: 350.0).animate(_animationController)
  ..addListener(() {
    this.setState(() {});
  })
  ..addStatusListener(
    (AnimationStatus status) {
      if (status == AnimationStatus.dismissed) {
        
      }...
    },
  );
複製程式碼

AnimationController

建立一個動畫,離不開控制器AnimationController。

  • 它會產生數值 0 -- 1 區間內的數值。
  • 控制動畫 reverse(), forward(), animateTo(), stop()
  • 繼承Animation<double>
  • 切記路由銷燬時需要釋放動畫資源
AnimationController _animationController = AnimationController(
  duration: Duration(milliseconds: _duration),
  vsync: this,
);
複製程式碼

Tween

如上面的程式碼, Tween接收begin和end兩個引數,不僅可以是數值型別,也可以使用ColorTween, RectTween, BorderTween, AlignmentTween等接收Color, Rect, Border, Alignment等型別。

  • animate()

    animate方法傳入Animation<double>,返回Animation<T>型別

  • 繼承Animatable<T>

ColorTween _colorTween = ColorTween(
  begin: Color(0xFFC1C1C1),
  end: Color(0xFFC19426),
);
複製程式碼

Curves

動畫過程可以是勻速的、勻加速的或者先加速後減速等。通過Curve(曲線)來描述動畫過程,我們把勻速動畫稱為線性的(Curves.linear), 而非勻速動畫稱為非線性的。

AnimationController _controller = AnimationController(
  duration: Duration(milliseconds: _duration),
  vsync: this,
);
Animation _curvedAnimation = CurvedAnimation(
  parent: _controller,
  curve: Curves.easeIn,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(_curvedAnimation);
複製程式碼

Ticker

當建立AnimationController時, 需要傳遞一個vsync引數,它接收一個TickerProvider型別的物件,它的主要職責是建立Ticker.

通常我們使用State with SingleTickerProviderStateMixin,然後將State物件作為vsync的值。

class AnimationDialog extends StatefulWidget {
  @override
  AnimationDialogState createState() => AnimationDialogState();
}

class AnimationDialogState extends State<AnimationDialog>
    with SingleTickerProviderStateMixin {
    /// Animation Controller
    AnimationController _animationController = AnimationController(
        duration: Duration(milliseconds: 500),
        vsync: this,
    );
}

複製程式碼

AnimatedWidget

使用Animation的時候,一般使用addListener更新當前的State

animation.addListener(() {
  setState(() {
    // 
  });
});
複製程式碼

這就是AnimatedWidget的作用,AnimatedWidget繼承StatefulWidget,並接收Listenable物件,而Animation是繼承Listenable的。

使用方法:目標Widget繼承AnimatedWidget,接收AnimatedWidget引數。

class AnimatedLogo extends AnimatedWidget {
  /// Animation
  final Animation<double> animation;

  AnimatedLogo({Key key, this.animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    return Center(
      child: Container(
        margin: EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,
        width: animation.value,
        child: FlutterLogo(),
      ),
    );
  }
}
複製程式碼

AnimatedBuilder

在使用AnimatedWidget時,需要把目標Widget繼承AnimatedWidget,這樣寫多少有點麻煩。如果封裝一個Common類,接收animation物件和child,這就有了AnimatedWidget. Flutter中正是通過這樣的方式封裝了很多動畫,如:FadeTransition、ScaleTransition、SizeTransition、RotationTransition等,很多時候都可以複用這些過渡類。

class GrowTransition extends StatelessWidget {
  GrowTransition({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
      ),
    );
  }
}
複製程式碼

Transform

Transform可以對子元件實現一些特效。

詳情請參考官方介紹: book.flutterchina.club/chapter5/tr…

Container(
  color: Colors.black,
  child: new Transform(
    alignment: Alignment.topRight, //相對於座標系原點的對齊方式
    transform: new Matrix4.skewY(0.3), //沿Y軸傾斜0.3弧度
    child: new Container(
      padding: const EdgeInsets.all(8.0),
      color: Colors.deepOrange,
      child: const Text('Apartment for rent!'),
    ),
  ),
);
複製程式碼

Flutter動畫及示例

  • rotate

    Transform.rotate可以對子元件進行旋轉變換。

  • scale

    Transform.scale可以對子元件進行縮小或放大。

  • translate

    Transform.translate接收一個offset引數,可以在繪製時沿x、y軸對子元件平移一定的距離。

動畫示例:

卡片彈出動畫對話方塊

實現方案:高度在持續變化的對話方塊

擴充套件:對話方塊可以從底部、上部、中間等位置出現。

主要程式碼:

Container(
    height: _animation?.value ?? 0.0,
    alignment: Alignment.bottomCenter,
    child: SingleChildScrollView(
      child: Container(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            _buildCardWidget(),
            _buildBottomWidget(),
          ],
        ),
      ),
    ),
  );
複製程式碼

Animation Dialog

參考網址:

動畫·《Flutter實戰》:book.flutterchina.club/chapter9/an…

以上程式碼地址:github.com/smiling1990…

相關文章