Flutter入门:动画相关
動畫
在flutter中,如果想讓某個widget執行動畫,需要用一個動畫類的widget封裝一下,比如一個圖片
Center(child: Image.asset(xxxxxx), ),想實現透明度動畫,使用FadeTransition,如下
Center(child: FadeTransition(opacity: _speakAnimation,child: Image.asset(R.assetsLiveSpeak),), ),關鍵是opacity,是一個Animation,要想實現一個動畫,還需要一個Tween和一個AnimationController。
Tween就是Animation。Tween還需要一個AnimationController,他們的創建及定義如下:
class _XXX extends State<XXXX> with SingleTickerProviderStateMixin{AnimationController _speakController;Animation _speakAnimation;@overridevoid initState() {super.initState();_speakController = AnimationController(vsync: this,duration: Duration(seconds: 2),);_speakAnimation = Tween(begin: 1.0,end: 0.0,).animate(_speakController);_speakAnimation.addStatusListener((status) { //監聽動畫if(status == AnimationStatus.completed){//todo}});}...可以看到Tween定義的是動畫的起始和結束狀態(這里就是透明度的值)。而AnimationController主要是定義時長。
另外Tween可以添加動畫監聽(addStatusListener),一共有四種狀態
enum AnimationStatus {/// The animation is stopped at the beginning.dismissed,/// The animation is running from beginning to end.forward,/// The animation is running backwards, from end to beginning.reverse,/// The animation is stopped at the end.completed, }但是這樣還差最后一步,啟動動畫,因為我們需求是頁面一展示即播放,所以在build函數中forward一下即可(當然還可以在其他時機播放),代碼如下:
class _XXX extends State<XXXX> with SingleTickerProviderStateMixin{AnimationController _speakController;Animation _speakAnimation;@overridevoid initState() {super.initState();_speakController = AnimationController(vsync: this,duration: Duration(seconds: 2),);_speakAnimation = Tween(begin: 1.0,end: 0.0,).animate(_speakController);_speakAnimation.addStatusListener((status) {if(status == AnimationStatus.completed){//todo}});}...Widget build(BuildContext context) {_speakController.forward(); //播放動畫return Stack(children: <Widget>[Center(child: FadeTransition(opacity: _speakAnimation,child: Image.asset(R.assetsLiveSpeak),),),...動畫卡頓
從今天的一個需求說起吧,實現一個按鈕呼吸效果,很簡單,就是使用一個縮放動畫即可,如下:
class _xxx extends State<xxx> with SingleTickerProviderStateMixin{AnimationController _animationController;Animation _animation;@overridevoid initState() {super.initState();_animationController = AnimationController(vsync: this,duration: Duration(milliseconds: 800),);_animation = Tween(begin: 0.8,end: 1.0,).animate(_animationController);}@overridevoid dispose() {_animationController.dispose();super.dispose();}@overrideWidget build(BuildContext context) {_animationController.repeat(reverse: true);return Stack(alignment: Alignment.center,children: [...Column(children: [...ScaleTransition(scale: _animation,child: TextButton(onPressed: widget.onOpen,child: Container(width: 120,height: 60,padding: EdgeInsets.only(bottom: 8),alignment: Alignment.center,decoration: BoxDecoration(image: DecorationImage(image: AssetImage(R.assetsLiveRedPackageBtn))),child: Text("領取",style: TextStyle(fontSize: 22,fontWeight: FontWeight.bold,color: Color(0xFFB34D35)),),),),),...],)],);} }動畫效果是從0.8倍擴大到1.0,然后reverse,一直repeat即可。
但是運行后發現動畫出現了異常,動畫擴大到1.0后會快速小幅度縮放一次,然后才會還原到0.8
這明顯不是我們想要的動畫效果,后來我們嘗試了其他動畫,都有類似的效果。
但是在其他頁面上的動畫就不會出問題,所以最后排查發現是該頁面的定時器影響到了動畫。
這個頁面里有一個倒計時,通過Timer來更新其中倒計時的文字,而更新使用了setState進行重繪,這樣在動畫執行到1秒的時候(擴大到1.0又縮回一點的時候)倒計時更新了,由于是setState,所以動畫widget也重繪了(這樣又變回1.0大小了),然后才縮回0.8
解決方法就是新增一個StatefulWidget類,將Timer和倒計時相關的組件放到這個類中實現,這樣倒計時更新只會刷新這一部分,不會刷新動畫組件,如下:
class TimerText extends StatefulWidget{int time;TimerText(this.time);@overrideState<StatefulWidget> createState() {return _TimerText();} }class _TimerText extends State<TimerText>{Timer timer;@overridevoid initState() {super.initState();timer = Timer.periodic(Duration(seconds: 1), (timer) {setState(() {if(widget.time <= 0){timer.cancel();}else{widget.time--;}});});}@overridevoid dispose() {timer.cancel();super.dispose();}@overrideWidget build(BuildContext context) {return Text("${widget.time}s",style: TextStyle(fontSize: 14,color: Color(0xFFF9D873)),);}}關注公眾號:BennuCTech,獲取更多干貨!
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的Flutter入门:动画相关的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FLutter入门:异步加载组件Futu
- 下一篇: getExternalFilesDir到