flutter動畫:抖動,背景閃爍塘辅,圓角變化

寫在前面

適用于對flutter動畫有一定了解的同學,本案例是為了模擬一個角色對象根據(jù)不同狀態(tài)變換不同效果

先看下效果圖


0jjg5-ur642.gif

實現(xiàn)&代碼

定義狀態(tài)&動畫

enum CellStatus { none, mot, pen, def }
  • non: none/常規(guī)狀態(tài)皆撩,無動畫
  • mot: motion/行動狀態(tài)扣墩,背景閃爍
  • pen: pending/待選狀態(tài),抖動
  • def: defense/防守狀態(tài)扛吞,尖角變圓角

定義角色對象

class Cell {
  CellStatus status;
  Notify1<CellStatus> onStatusChanged;
}

本例中只包含兩個屬性

  • status: CellStatus呻惕,表示當前狀態(tài)
  • onStatusChanged: Notify1<CellStatus>,表示狀態(tài)變化的回調
    這里的Notify1是自定義的一個帶一個泛型參數(shù)的方法對象

當需要變化狀態(tài)時滥比,比如轉換到行動狀態(tài)

cell.onStatusChanged?.call(CellStatus.mot)

其實更常見的辦法是讓Cell繼承于ChangeNotifier亚脆,然后通過addListener來添加監(jiān)聽變化,相比于onStatusChanged: Notify1<CellStatus>盲泛,后者只針對單一屬性濒持,具有指向性。

頁面布局

上方是4個按鈕寺滚,模擬狀態(tài)變化柑营,下方是展示角色對象的CellWidget

class CellApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// 這里創(chuàng)建角色對象
    Cell cell = Cell();
    var children = [
      Spacer(),
      RaisedButton(onPressed: () => cell.onStatusChanged?.call(CellStatus.none), child: Text("None")),
      Spacer(),
      RaisedButton(onPressed: () => cell.onStatusChanged?.call(CellStatus.mot), child: Text("Mot")),
      Spacer(),
      RaisedButton(onPressed: () => cell.onStatusChanged?.call(CellStatus.pen), child: Text("Pen")),
      Spacer(),
      RaisedButton(onPressed: () => cell.onStatusChanged?.call(CellStatus.def), child: Text("Def")),
      Spacer(),
    ];
    return Scaffold(
        body: SafeArea(
      child: Column(children: [
        Expanded(child: Center(child: Row(children: children, mainAxisSize: MainAxisSize.min))),
        Expanded(child: Container(alignment: Alignment.topCenter, child: CellWidget(cell)))
      ]),
    ));
  }
}

CellWidget

這是一個需要應用動畫的widget,傳入Cell對象玛迄。其State中加入AnimationController

class CellWidget extends StatefulWidget {
  final Cell cell;

  CellWidget(this.cell);

  @override
  _CellWidgetState createState() => _CellWidgetState();
}

class _CellWidgetState extends State<CellWidget> with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 500));
    _controller.addListener(() => setState(() {}));
  }

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

  @override
  Widget build(BuildContext context) {
    ...
  }

監(jiān)聽狀態(tài)變化

就是為cell.onStatusChanged賦值

  @override
  void initState() {
    super.initState();
    ...
    widget.cell.onStatusChanged = onStatusChanged;
  }

  void onStatusChanged(CellStatus newStatus) {
    ...
  }

處理狀態(tài)變化

其實就是創(chuàng)建根據(jù)狀態(tài)創(chuàng)建Animation

  • 當為motion時由境,創(chuàng)建背景閃爍動畫,使用ColorTween創(chuàng)建開始和結束的顏色蓖议,并調用controller.repeat(reverse: true)來實現(xiàn)重復
  • 當為pending時虏杰,抖動動畫是通過四向隨機改變widget位置來實現(xiàn)的,所以只需在每次重繪時通過Random#nextInt()來隨機方向即可勒虾,此處不用創(chuàng)建任何動畫纺阔,只需讓controller重復即可
  • 當為defense時,尖角變圓角修然,使用Tween創(chuàng)建開始和結束時圓角的半徑即可笛钝,不需重復
  • 而none狀態(tài),需要回歸正常愕宋,由于正常值是預定義的玻靡,所以此處僅僅需要關閉動畫
  void onStatusChanged(CellStatus newStatus) {
    print("cell status change from ${widget.cell.status.toString()} to ${newStatus.toString()}");
    widget.cell.status = newStatus;
    setState(() {});
    _controller.reset();
    _controller.duration = Duration(milliseconds: 200);
    if (widget.cell.status == CellStatus.mot) {
      _animation = ColorTween(begin: Colors.white, end: Colors.red)
          .animate(CurvedAnimation(parent: _controller, curve: Curves.easeInCubic));
      _controller.repeat(reverse: true);
    } else if (widget.cell.status == CellStatus.none) {
      _controller.stop();
    } else if (widget.cell.status == CellStatus.pen) {
      _controller.repeat(reverse: true);
    } else if (widget.cell.status == CellStatus.def) {
      _animation = Tween(begin: 0.0, end: 16.0).animate(_controller);
      _controller.duration = Duration(milliseconds: 800);
      _controller.forward();
    }
  }

build不同狀態(tài)下的widget

正常情況下,應該是一個Container中贝,寬高為64.0囤捻,居中一個Text,decoration為白底邻寿,邊框為尖角
由于抖動動畫需要改變位置蝎土,所以外層應當加Transform.translate(offset, widget)

  @override
  Widget build(BuildContext context) {
    var color = Colors.white;
    var offset = Offset.zero;
    var radius = 0.0;
    if (widget.cell.status == CellStatus.mot) {
      color = _animation.value;
    } else if (widget.cell.status == CellStatus.pen) {
      var random = new Random().nextInt(4);
      /// left:0 right:1 top:2 bottom:3
      double x = 0, y = 0;
      switch (random) {
        case 0: x = -2; break;
        case 1: x = 2; break;
        case 2: y = -2; break;
        case 3: y = 2; break;
      }
      offset = offset.translate(x, y);
    } else if (widget.cell.status == CellStatus.def) {
      radius = _animation.value;
    }
    var decoration = BoxDecoration(color: color, border: Border.all(color: Colors.blue), borderRadius: BorderRadius.circular(radius));
    var container = Container(width: 64.0, height: 64.0, decoration: decoration, alignment: Alignment.center, child: Text("Cell"));
    return Transform.translate(offset: offset, child: container);
  }

最后

本人熱愛編程视哑,熱愛游戲,熱愛flutter誊涯,一直想用flutter寫一個RPG類型的游戲挡毅,有喜歡flutter開發(fā)游戲的朋友可以加我好友互相交流哈!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末暴构,一起剝皮案震驚了整個濱河市跪呈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌丹壕,老刑警劉巖庆械,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異菌赖,居然都是意外死亡缭乘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門琉用,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堕绩,“玉大人,你說我怎么就攤上這事邑时∨簦” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵晶丘,是天一觀的道長黍氮。 經(jīng)常有香客問我,道長浅浮,這世上最難降的妖魔是什么沫浆? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮滚秩,結果婚禮上专执,老公的妹妹穿的比我還像新娘。我一直安慰自己郁油,他們只是感情好本股,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著桐腌,像睡著了一般拄显。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上案站,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天躬审,我揣著相機與錄音,去河邊找鬼。 笑死盒件,一個胖子當著我的面吹牛,可吹牛的內容都是我干的舱禽。 我是一名探鬼主播炒刁,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼誊稚!你這毒婦竟也來了翔始?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤里伯,失蹤者是張志新(化名)和其女友劉穎城瞎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疾瓮,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡脖镀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了狼电。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜒灰。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肩碟,靈堂內的尸體忽然破棺而出强窖,到底是詐尸還是另有隱情,我是刑警寧澤削祈,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布翅溺,位于F島的核電站,受9級特大地震影響髓抑,放射性物質發(fā)生泄漏咙崎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一启昧、第九天 我趴在偏房一處隱蔽的房頂上張望叙凡。 院中可真熱鬧,春花似錦密末、人聲如沸握爷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽新啼。三九已至,卻和暖如春刹碾,著一層夾襖步出監(jiān)牢的瞬間燥撞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留物舒,地道東北人色洞。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像冠胯,于是被迫代替她去往敵國和親火诸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內容

  • 邂逅FLutter 萬物皆是Widget 一般縮進2個空格 文字居中 Widget Center() Materi...
    JackLeeVip閱讀 3,178評論 0 4
  • 1. 基本動畫概念和相關類 Animation: flutter 動畫庫中的一個核心類荠察,它生成指導動畫的值置蜀; An...
    IAMCJ閱讀 1,340評論 0 8
  • 目錄 一、Flutter 為何使用Dart開發(fā)語言二悉盆、Flutter的UI系統(tǒng)1.特點2.架構簡介2.1 Flut...
    十拿九穩(wěn)啦閱讀 3,662評論 3 28
  • 如何安裝 Flutter 請點擊這里 1盯荤、Flutter 是什么? Flutter是一款移動應用程序SDK焕盟,包含框...
    大王叫我來巡山_Cong閱讀 1,377評論 0 9
  • 久違的晴天秋秤,家長會。 家長大會開好到教室時脚翘,離放學已經(jīng)沒多少時間了航缀。班主任說已經(jīng)安排了三個家長分享經(jīng)驗。 放學鈴聲...
    飄雪兒5閱讀 7,523評論 16 22