Flutter 134: 圖解動(dòng)畫小插曲之 SVGA 動(dòng)畫

????小菜之前嘗試了 FlareLottie 動(dòng)畫,實(shí)現(xiàn)效果都很高效;今天小菜嘗試另一種思路 SVGA 動(dòng)畫;SVGA 是一種同時(shí)兼容 iOS / Android / Flutter / Web 多個(gè)平臺(tái)的動(dòng)畫格式;

SVGA

基本簡(jiǎn)介

????小菜首先贊美一下 SVGA 官網(wǎng),非常簡(jiǎn)潔而且主要信息都容易查到,同時(shí)看著非常舒服;設(shè)計(jì)師通過 AE 等工具設(shè)計(jì)生成好 SVGA 動(dòng)畫后,可直接交付給開發(fā)同學(xué)通過 SVGAPlayer 直接調(diào)用即可,集成和應(yīng)用都很簡(jiǎn)單;

????SVGA 提供了在線動(dòng)畫素材預(yù)覽以及素材元素拆分,還可以將 SVGA 動(dòng)畫轉(zhuǎn)化為 SVG 矢量圖元素,非常靈活方便;

案例嘗試

????SVGA 提供了多種方式完整的集成方案,小菜簡(jiǎn)單嘗試一下 Flutter 版本應(yīng)用;

1. 集成 svgaplayer_flutter

????與所有插件使用相同,小菜引入對(duì)應(yīng)版本的 svgaplayer_flutter;目前 svgaplayer_flutter 已支持 Flutter 2.0 空安全;

svgaplayer_flutter: ^2.1.2

2. 應(yīng)用播放 SVGA

2.1 SVGASimpleImage 加載動(dòng)畫

????svgaplayer_flutter 支持播放本地動(dòng)畫和網(wǎng)絡(luò)線上動(dòng)畫,與 Image 加載本地和網(wǎng)絡(luò)圖片類似;SVGA 提供了封裝好 SVGAAnimationController 控制器的 SVGASimpleImage;根據(jù)文件類型,通過不同參數(shù)進(jìn)行展示,默認(rèn)動(dòng)畫效果為重復(fù)播放;

class SVGASimpleImage extends StatefulWidget {
  final String resUrl;
  final String assetsName;
  final File file;

  SVGASimpleImage({Key key, this.resUrl, this.assetsName, this.file}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _SVGASimpleImageState();
}

????簡(jiǎn)單分析源碼可得,SVGASimpleImage 根據(jù)傳遞的不同動(dòng)畫路徑進(jìn)行不同方式的展示,通過 SVGAParser.shared 加載和解碼不同類型的網(wǎng)絡(luò)資源、本地資源以及 File 資源等;

class _SVGAPageState extends State<SVGAPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('SVGA Page')),
        body: Column(children: [
          _itemSVGA01(false, 'images/posche.svga'),
          _itemSVGA01(true, 'https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true')
        ]));
  }

  _itemSVGA01(isUrl, svgaUrl) {
    return Expanded( flex: 1,
        child: SVGASimpleImage(assetsName: isUrl ? null : svgaUrl, resUrl: isUrl ? svgaUrl : null));
  }
}
2.2 SVGAImage & SVGAAnimationController

????SVGASimpleImage 是將 SVGAImageSVGAAnimationController 封裝好的動(dòng)畫播放器,若我們想自由控制動(dòng)畫的播放、暫停、重播等操作的話,需要配合 SVGAAnimationController 控制器調(diào)節(jié)動(dòng)畫的播放過程;

SVGAImage(
    this._controller, {
    this.fit = BoxFit.contain,
    this.clearsAfterStop = true,
})

????簡(jiǎn)單分析源碼可得,SVGAImage 主要是通過 SVGAAnimationController 來進(jìn)行動(dòng)畫播放;與圖片類似,可以通過 BoxFit 設(shè)置動(dòng)畫的布局樣式;

????SVGAAnimationController 是對(duì) AnimationController 進(jìn)一層封裝與應(yīng)用,調(diào)用的方法和狀態(tài)回調(diào)基本是一致的;

enum AnimationStatus {
  /// 動(dòng)畫開始時(shí)結(jié)束
  dismissed,

  /// 動(dòng)畫開始
  forward,

  /// 逆向動(dòng)畫
  reverse,

  /// 動(dòng)畫完成結(jié)束
  completed,
}

this.animationController ?.addStatusListener((status) => print('---status---$status'));

????SVGAAnimationController 提供了常用的播放方法,小菜簡(jiǎn)單嘗試幾種常用的;

  • reset 動(dòng)畫重置;
  • forward 動(dòng)畫播放,小菜建議若動(dòng)畫從頭開始播放先調(diào)用 reset 使動(dòng)畫重置,防止其他操作影響動(dòng)畫起始位置;
  • stop 動(dòng)畫停止,與 Lottie 動(dòng)畫不同,SVGAAnimationController 沒有提供對(duì)應(yīng)的暫停方法,小菜將 stop 理解為暫停和停止,若繼續(xù)播放則調(diào)用 forward 即可;
  • reverse 動(dòng)畫反轉(zhuǎn),即反向播放動(dòng)畫;
  • repeat 動(dòng)畫重復(fù);
  • fling 使用臨界阻尼彈簧和初始速度驅(qū)動(dòng)動(dòng)畫;小菜簡(jiǎn)單理解在正向播放時(shí),fling 會(huì)按起始速度播放完成;
@override
void initState() {
  super.initState();
  this.animationController = SVGAAnimationController(vsync: this)
    ..addListener(() {
      if (mounted) { setState(() {}); }
    });
  this._loadAnimation();
}

@override
void dispose() {
  this.animationController?.clear();
  this.animationController?.dispose();
  this.animationController = null;
  super.dispose();
}

void _loadAnimation() async {
  final videoItem = await _loadSVGA(false, 'images/posche.svga');
  if (mounted)
    setState(() {
      this.isLoading = false;
      this.animationController?.videoItem = videoItem;
      this.animationController ?.addStatusListener((status) => print('---status---$status'));
    });
}

Widget _itemBtn(str) => Expanded(
    child: Container(
        margin: EdgeInsets.all(1.0),
        child: FlatButton(
            color: Colors.lightBlueAccent,
            child: Text(str),
            onPressed: () {
              if (str == 'start') {
                animationController?.reset();
                animationController?.forward();
              } else if (str == 'reverse') {
                animationController?.reverse();
              } else if (str == 'repeat') {
                animationController?.repeat();
              } else if (str == 'resume') {
                animationController?.forward();
              } else if (str == 'stop') {
                animationController?.stop();
              } else if (str == 'fling') {
                animationController?.fling();
              }
              setState(() {});
            })));

SVAG & Lottie

????小菜查閱了一些資料,簡(jiǎn)單了解了 SVGALottie 動(dòng)畫實(shí)現(xiàn)方式的差異;SVGA 是將 SVGA 矢量圖逐幀繪制,通過設(shè)置幀率,來生成一個(gè)配置文件,使得每一幀都有一個(gè)配置,每一幀都是關(guān)鍵幀,通過幀率去刷每一幀的畫面,這個(gè)思路跟 GIF 很像,但是通過配置使得動(dòng)畫過程中圖片都可以得到復(fù)用;

????而 Lottie 動(dòng)畫是逐層繪制,將所有的動(dòng)畫拆成多個(gè)層級(jí),每個(gè)層級(jí) layer 都有一個(gè)動(dòng)畫配置,播放時(shí)解析多 0 個(gè) layer 的配置,并給每個(gè) layer 做相應(yīng)的動(dòng)畫;

????兩種動(dòng)畫模式都是很成熟且應(yīng)用范圍很廣的動(dòng)畫,小菜因未找到完全相同的動(dòng)畫元素,未能進(jìn)行準(zhǔn)確的數(shù)據(jù)分析,但查閱資料兩者性能基本持平,具體選用哪種根據(jù)實(shí)際情況而定;


????SVGA 案例源碼


????小菜對(duì) SVGA 的研究還很淺顯,有很多方法未研究到;如有錯(cuò)誤,請(qǐng)多多指導(dǎo)!

來源: 阿策小和尚

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容