網站首頁 編程語言 正文
前言
在網絡速度較慢的場景,一個有趣的加載會提高用戶的耐心和對 App 的好感,有些 loading
動效甚至會讓用戶有想弄清楚整個動效過程到底是怎么樣的沖動。然而,大部分的 App的 loading
就是下面這種千篇一律的效果 —— 俗稱“轉圈”。
本篇我們利用Flutter 的 PathMetric
來玩幾個有趣的 loading
效果。
效果1:圓環內滾動的球
如上圖所示,一個紅色的小球在藍色的圓環內滾動,而且在往上滾動的時候速度慢,往下滾動的時候有個明顯的加速過程。這個效果實現的思路如下:
- 繪制一個藍色的圓環,在藍色的圓環內構建一個半徑更小一號的圓環路徑(Path)。
- 讓紅色小球在動畫控制下沿著內部的圓環定義的路徑運動。
- 選擇一個中間減速(上坡)兩邊加速的動畫曲線。
下面是實現代碼:
// 動畫控制設置 controller = AnimationController(duration: const Duration(seconds: 3), vsync: this); animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation( parent: controller, curve: Curves.slowMiddle, )) ..addListener(() { setState(() {}); }); // 繪制和動畫控制方法 _drawLoadingCircle(Canvas canvas, Size size) { var paint = Paint()..style = PaintingStyle.stroke ..color = Colors.blue[400]! ..strokeWidth = 2.0; var path = Path(); final radius = 40.0; var center = Offset(size.width / 2, size.height / 2); path.addOval(Rect.fromCircle(center: center, radius: radius)); canvas.drawPath(path, paint); var innerPath = Path(); final ballRadius = 4.0; innerPath.addOval(Rect.fromCircle(center: center, radius: radius - ballRadius)); var metrics = innerPath.computeMetrics(); paint.color = Colors.red; paint.style = PaintingStyle.fill; for (var pathMetric in metrics) { var tangent = pathMetric.getTangentForOffset(pathMetric.length * animationValue); canvas.drawCircle(tangent!.position, ballRadius, paint); } }
效果2:雙軌運動
上面的實現效果其實比較簡單,就是繪制了一個圓和一個橢圓,然后讓兩個實心圓沿著路徑運動。因為有了這個組合效果,趣味性增加不少,外面的橢圓看起來就像是一條衛星軌道一樣。實現的邏輯如下:
- 繪制一個圓和一個橢圓,二者的中心點重合;
- 在圓和橢圓的路徑上分別繪制一個小的實心圓;
- 通過動畫控制實心圓沿著大圓和橢圓的路徑上運動。
具體實現的代碼如下所示。
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation( parent: controller, curve: Curves.easeInOutSine, )) ..addListener(() { setState(() {}); }); _drawTwinsCircle(Canvas canvas, Size size) { var paint = Paint() ..style = PaintingStyle.stroke ..color = Colors.blue[400]! ..strokeWidth = 2.0; final radius = 50.0; final ballRadius = 6.0; var center = Offset(size.width / 2, size.height / 2); var circlePath = Path() ..addOval(Rect.fromCircle(center: center, radius: radius)); paint.style = PaintingStyle.stroke; paint.color = Colors.blue[400]!; canvas.drawPath(circlePath, paint); var circleMetrics = circlePath.computeMetrics(); for (var pathMetric in circleMetrics) { var tangent = pathMetric .getTangentForOffset(pathMetric.length * animationValue); paint.style = PaintingStyle.fill; paint.color = Colors.blue; canvas.drawCircle(tangent!.position, ballRadius, paint); } paint.style = PaintingStyle.stroke; paint.color = Colors.green[600]!; var ovalPath = Path() ..addOval(Rect.fromCenter(center: center, width: 3 * radius, height: 40)); canvas.drawPath(ovalPath, paint); var ovalMetrics = ovalPath.computeMetrics(); for (var pathMetric in ovalMetrics) { var tangent = pathMetric.getTangentForOffset(pathMetric.length * animationValue); paint.style = PaintingStyle.fill; canvas.drawCircle(tangent!.position, ballRadius, paint); } }
效果3:鐘擺運動
鐘擺運動的示意圖如下所示,一條繩子系著一個球懸掛某處,把球拉起一定的角度釋放后,球就會帶動繩子沿著一條圓弧來回運動,這條圓弧的半徑就是繩子的長度。
這個效果通過代碼來實現的話,需要做下面的事情:
- 繪制頂部的橫線,代表懸掛的頂點;
- 繪制運動的圓弧路徑,以便讓球沿著圓弧運動;
- 繪制實心圓代表球,并通過動畫控制沿著一條圓弧運動;
- 用一條頂端固定,末端指向球心的直線代表繩子;
- 當球運動到弧線的終點后,通過動畫反轉(
reverse
)控制球 返回;到起點后再正向(forward
) 運動就可以實現來回運動的效果了。
具體實現的代碼如下,這里在繪制球的時候給 Paint
對象增加了一個 maskFilter
屬性,以便讓球看起來發光,更加好看點。
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation( parent: controller, curve: Curves.easeInOutQuart, )) ..addListener(() { setState(() {}); } ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); _drawPendulum(Canvas canvas, Size size) { var paint = Paint() ..style = PaintingStyle.stroke ..color = Colors.blue[400]! ..strokeWidth = 2.0; final ceilWidth = 60.0; final pendulumHeight = 200.0; var ceilCenter = Offset(size.width / 2, size.height / 2 - pendulumHeight / 2); var ceilPath = Path() ..moveTo(ceilCenter.dx - ceilWidth / 2, ceilCenter.dy) ..lineTo(ceilCenter.dx + ceilWidth / 2, ceilCenter.dy); canvas.drawPath(ceilPath, paint); var pendulumArcPath = Path() ..addArc(Rect.fromCircle(center: ceilCenter, radius: pendulumHeight), 3 * pi / 4, -pi / 2); paint.color = Colors.white70; var metrics = pendulumArcPath.computeMetrics(); for (var pathMetric in metrics) { var tangent = pathMetric.getTangentForOffset(pathMetric.length * animationValue); canvas.drawLine(ceilCenter, tangent!.position, paint); paint.style = PaintingStyle.fill; paint.color = Colors.blue; paint.maskFilter = MaskFilter.blur(BlurStyle.solid, 4.0); canvas.drawCircle(tangent.position, 16.0, paint); } }
總結
本篇介紹了三種 Loading 動效的繪制邏輯和實現代碼,可以看到利用路徑屬性進行繪圖以及動畫控制可以實現很多有趣的動畫效果。
原文鏈接:https://juejin.cn/post/7125029565625270286
相關推薦
- 2023-01-28 架構師說比起404我們更怕200錯誤_相關技巧
- 2022-10-02 react如何獲取state的值并更新使用_React
- 2022-03-13 .NET中IoC框架Autofac用法講解_自學過程
- 2022-04-22 R語言繪制Radar?chart雷達圖_R語言
- 2023-03-17 使用c語言輕松實現動態內存管_C 語言
- 2022-05-14 C++使用new和delete進行動態內存分配與數組封裝_C 語言
- 2022-05-13 C++ 減少臨時字符串對象的產生
- 2023-11-11 【數據處理】Python matplotlib繪制雙柱狀圖以及繪制堆積柱狀圖——保姆級教程
- 最近更新
-
- 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同步修改后的遠程分支