網站首頁 編程語言 正文
為了追求更好的用戶體驗,有時候我們需要一個類似心跳一樣跳動著的控件來吸引用戶的注意力,這是一個小小的優化需求,但是在 Flutter 里動畫兩件套就像裹腳布一樣臭長,所以需要像封裝一個 AnimatedWidget,解放生產力。
實現動畫
混入 SingleTickerProviderStateMixin
當創建一個 AnimationController 時,需要傳遞一個vsync
參數,存在vsync
時會防止動畫的UI不在當前屏幕時消耗不必要的資源。 通過混入 SingleTickerProviderStateMixin 。
class _MyHomePageState extends Statewith SingleTickerProviderStateMixin{}
創建動畫
創建一個間隔將近一秒鐘的動畫控制器:
late final AnimationController animController; @override void initState() { super.initState(); animController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); }
心跳動畫是從小變大,再變小,所以需要一個值大小變化的動畫:
late final Animationanimation; @override void initState() { super.initState(); animController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); animation = Tween ( begin: 0.9, end: 1.05, ); }
心跳是不間斷的,所以需要監聽動畫完成時恢復動畫,再繼續開始動畫:
animation = Tween( begin: 0.9, end: 1.05, ).animate(animController) ..addListener(() { setState(() {}); }) ..addStatusListener((status) { if (status == AnimationStatus.completed) { animController.reverse(); } else if (status == AnimationStatus.dismissed) { animController.forward(); } });
使用縮放控件:
Transform.scale( scale: animation.value, child: const FlutterLogo( size: 80, ), ),
為了跳動效果,突出跳動動畫,把縮回去的時間改短:
animController = AnimationController( reverseDuration: const Duration(milliseconds: 700), duration: const Duration(milliseconds: 800), vsync: this, );
最后別忘了釋放資源:
@override void dispose() { animController.dispose(); super.dispose(); }
抽離成小組件
為了每次用到類似的動畫只需引入即可,需要分離動畫和顯示的組件。新建一個BounceWidget
,包含動畫,然后可以傳入UI組件:
class BounceWidget extends StatefulWidget { final Widget child; const BounceWidget({ Key? key, required this.child, }) : super(key: key); @override StatecreateState() => _BounceWidgetState(); }
繼續實現動畫:
class _BounceWidgetState extends Statewith SingleTickerProviderStateMixin { late Animation animation; late AnimationController animController; @override void initState() { super.initState(); animController = AnimationController( reverseDuration: const Duration(milliseconds: 700), duration: const Duration(milliseconds: 800), vsync: this, ); animation = Tween ( begin: 0.9, end: 1.05, ).animate(animController) ..addListener(() { setState(() {}); }) ..addStatusListener((status) { if (status == AnimationStatus.completed) { animController.reverse(); } else if (status == AnimationStatus.dismissed) { animController.forward(); } }); animController.forward(); } @override Widget build(BuildContext context) { return Transform.scale( scale: animation.value, child: widget.child, ); } @override void dispose() { animController.dispose(); super.dispose(); } }
去引入動畫:
Center( child: BounceWidget( child: FlutterLogo( size: 80, ), ),
完整代碼
void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override StatecreateState() => _MyHomePageState(); } class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Padding( padding: const EdgeInsets.only(top: 80, left: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( "心動的", style: TextStyle( fontSize: 28, color: Colors.black, ), ), Text( "感覺", style: TextStyle( fontSize: 48, color: Colors.black, ), ), Center( child: BounceWidget( child: FlutterLogo( size: 80, ), ), ), ], ), ), ); } }
原文鏈接:https://juejin.cn/post/7083418319159722020
相關推薦
- 2022-05-19 Python中的logging模塊實現日志打印_python
- 2022-04-19 Windows中Python上傳文件到Liunx下的fastdfs
- 2023-06-17 C或C++報錯:ld?returned?1?exit?status報錯的原因及解決方法_C 語言
- 2023-03-28 python數組如何添加整行或整列_python
- 2022-03-14 JasperReport報表導出PDF中文不顯示的問題
- 2022-08-01 Python+Selenium鍵盤鼠標模擬事件操作詳解_python
- 2023-05-06 react中定義變量并使用方式_React
- 2022-08-01 詳解Selenium中元素定位方式_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支