Flutter(Flare) 最有趣用戶交互動畫沒有之一

flutter flare cover

2019年12月12日,FlutterFlutter Interact '19 上發(fā)布了如何使用 RiveFlutter 制作動態(tài)可交互的動畫經(jīng)驗分享,我看了之后,覺得非常有趣,因此,寫了3個小 demo,把它寫成文章記錄分享給大家。

名詞理解

首先,我們來理解幾個名詞,不然后續(xù)文章,可能看著有些暈,如下:

  • Flare:是 Flutter 的動畫插件名稱,完整名稱是 flare_flutter 我們要在 pubspec.yaml 文件里引入
  • Rive:是制作 Flare 動畫的網(wǎng)站,它既是一個網(wǎng)站也是制作工具,在此網(wǎng)站里有很多用戶分享 Flare 動畫供我們下載使用、Flare API使用文檔、制作 Flare 動畫的視頻教程(大家也可以通過學(xué)習(xí)制作自己喜歡的動畫)等

交互動畫預(yù)覽

登錄交互動畫

登錄交互動畫,包含如下6種動畫:

  • idle:無任何操作時的狀態(tài)(熊的身體會上下浮動和眨眼睛)
  • test:當(dāng)我們在 email 輸入框中輸入時的狀態(tài)(熊會看向輸入框,且隨著你輸入的長度旋轉(zhuǎn)頭部)
  • hands_up:當(dāng)我們在 password 輸入框中輸入時的狀態(tài) (熊會用手蒙上眼睛)
  • hands_down:當(dāng)我們在 password 輸入框輸入完成時的狀態(tài) (熊會放下雙手)
  • fail:當(dāng)我們登錄失敗時的狀態(tài)(熊會做出難過的表情)
  • success:當(dāng)我們登錄成功時的狀態(tài)(熊會做出高興的表情)

以上6種狀態(tài),可以在 Rive 網(wǎng)站查看具體動畫,點擊進入查看

下面,我們來看看案例里實現(xiàn)動畫效果

idle:無任何操作時的狀態(tài),如圖:

idle

test:當(dāng)我們在 email 輸入框中輸入時的狀態(tài),如圖:

test

hands_up:當(dāng)我們在 password 輸入框中輸入時的狀態(tài),hands_down:當(dāng)我們在 password 輸入框輸入完成時的狀態(tài),如圖:

hands_up & hands_down

fail:當(dāng)我們登錄失敗時的狀態(tài),如圖:

fail

success:當(dāng)我們登錄成功時的狀態(tài),如圖:

success

Button交互動畫

button 交互動畫,如圖:

button

Menu交互動畫

menu 交互動畫,如圖:

menu

以上所有動畫,也可以 點擊觀看視頻

代碼實現(xiàn)

如何用代碼實現(xiàn),分為以下2個步驟:

  • 引入插件和資源:引入相關(guān)插件 flare_fluttersmart_flare
  • 編寫代碼:編寫相關(guān)代碼

引入插件和資源

引入插件和資源,如下:

dependencies:
  ...
  flare_flutter: ^2.0.4  # flare 插件
  smart_flare: any  # 對 flare API進行封裝的插件,使用少量的代碼即可實現(xiàn)交互動畫
  ...

assets:
  ...
  - assets/Teddy.flr
  - assets/button-animation.flr
  - assets/slideout-menu.flr
  ...

編寫代碼

由于,登錄交互動畫稍復(fù)雜一些,在此就不展示實現(xiàn)的代碼,如感興趣,可移步GitHub查看源碼

Button交互動畫代碼實現(xiàn)

button 交互動畫代碼實現(xiàn)如下:

import 'package:flutter/material.dart';
import 'package:smart_flare/actors/smart_flare_actor.dart';
import 'package:smart_flare/models.dart';

class FlareButtonDemo extends StatefulWidget {
  @override
  _FlareButtonDemoState createState() => _FlareButtonDemoState();
}

class _FlareButtonDemoState extends State<FlareButtonDemo> {
  @override
  Widget build(BuildContext context) {
    var animationWidth = 295.0;
    var animationHeight = 251.0;
    var animationWidthThirds = animationWidth / 3;
    var halfAnimationHeight = animationHeight / 2;

    var activeAreas = [

      ActiveArea(
        area: Rect.fromLTWH(0, 0, animationWidthThirds, halfAnimationHeight),
        debugArea: false,
        guardComingFrom: ['deactivate'],
        animationName: 'camera_tapped',
      ),

      ActiveArea(
          area: Rect.fromLTWH(animationWidthThirds, 0, animationWidthThirds, halfAnimationHeight),
          debugArea: false,
          guardComingFrom: ['deactivate'],
          animationName: 'pulse_tapped'),

      ActiveArea(
          area: Rect.fromLTWH(animationWidthThirds * 2, 0, animationWidthThirds, halfAnimationHeight),
          debugArea: false,
          guardComingFrom: ['deactivate'],
          animationName: 'image_tapped'),

      ActiveArea(
          area: Rect.fromLTWH(0, animationHeight / 2, animationWidth, animationHeight / 2),
          debugArea: false,
          animationsToCycle: ['activate', 'deactivate'],
          onAreaTapped: () {
            print('Button tapped!');
          })

    ];

    return Scaffold(
      appBar: AppBar(
        title: Text('Flare Button Demo'),
      ),
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: [
                Color(0x3fffeb3b),
                Colors.orange,
              ]),
        ),
        child: Align(
          alignment: Alignment.bottomCenter,
          child: SmartFlareActor(
            width: animationWidth,
            height: animationHeight,
            filename: 'assets/button-animation.flr',
            startingAnimation: 'deactivate',
            activeAreas: activeAreas,
          ),
        ),
      ),
    );
  }
}

Menu交互動畫代碼實現(xiàn)

menu 交互動畫代碼實現(xiàn),如下:

import 'package:flutter/material.dart';
import 'package:smart_flare/smart_flare.dart';

class FlareSidebarMenuDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print(MediaQuery.of(context).size.height);
    return Scaffold(
      body: Container(
        child: Align(
          alignment: Alignment.centerRight,
          child: PanFlareActor(
            width: MediaQuery.of(context).size.width / 2.366,
            height: MediaQuery.of(context).size.height,
            filename: 'assets/slideout-menu.flr',
            openAnimation: 'open',
            closeAnimation: 'close',
            direction: ActorAdvancingDirection.RightToLeft,
            threshold: 20.0,
            reverseOnRelease: true,
            completeOnThresholdReached: true,
            activeAreas: [
              RelativePanArea(
                  area: Rect.fromLTWH(0, .7, 1.0, .3), debugArea: false),
            ],
          ),
        ),
      ),
    );
  }
}

以上3個交互動畫案例的源碼,放在了我2年前寫的一個 Flutter案例 的項目里了,此項目現(xiàn)已維護起來,以后會長期更新,感興趣的小伙伴可以收藏,沒事時來看看可能會有新的發(fā)現(xiàn) ??

此篇文章到此結(jié)束,下篇文章計劃給大家分享,F(xiàn)lutter 里的路由,會總結(jié)歸納所有的路由使用方法,最后來封裝一個優(yōu)秀的路由管理類。

之后附上博客和項目地址,如下:

博客地址:https://h.lishaoy.net/flutter-flare
項目地址:https://github.com/persilee/flutter_pro

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

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