Android?Flutter繪制有趣的?loading加載動畫
前言
在網(wǎng)絡(luò)速度較慢的場景,一個(gè)有趣的加載會提高用戶的耐心和對 App 的好感,有些 loading 動效甚至?xí)層脩粲邢肱宄麄€(gè)動效過程到底是怎么樣的沖動。然而,大部分的 App的 loading 就是下面這種千篇一律的效果 —— 俗稱“轉(zhuǎn)圈”。


本篇我們利用Flutter 的 PathMetric來玩幾個(gè)有趣的 loading 效果。
效果1:圓環(huán)內(nèi)滾動的球

如上圖所示,一個(gè)紅色的小球在藍(lán)色的圓環(huán)內(nèi)滾動,而且在往上滾動的時(shí)候速度慢,往下滾動的時(shí)候有個(gè)明顯的加速過程。這個(gè)效果實(shí)現(xiàn)的思路如下:
- 繪制一個(gè)藍(lán)色的圓環(huán),在藍(lán)色的圓環(huán)內(nèi)構(gòu)建一個(gè)半徑更小一號的圓環(huán)路徑(Path)。
- 讓紅色小球在動畫控制下沿著內(nèi)部的圓環(huán)定義的路徑運(yùn)動。
- 選擇一個(gè)中間減速(上坡)兩邊加速的動畫曲線。
下面是實(shí)現(xiàn)代碼:
// 動畫控制設(shè)置
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:雙軌運(yùn)動

上面的實(shí)現(xiàn)效果其實(shí)比較簡單,就是繪制了一個(gè)圓和一個(gè)橢圓,然后讓兩個(gè)實(shí)心圓沿著路徑運(yùn)動。因?yàn)橛辛诉@個(gè)組合效果,趣味性增加不少,外面的橢圓看起來就像是一條衛(wèi)星軌道一樣。實(shí)現(xiàn)的邏輯如下:
- 繪制一個(gè)圓和一個(gè)橢圓,二者的中心點(diǎn)重合;
- 在圓和橢圓的路徑上分別繪制一個(gè)小的實(shí)心圓;
- 通過動畫控制實(shí)心圓沿著大圓和橢圓的路徑上運(yùn)動。
具體實(shí)現(xiàn)的代碼如下所示。
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:鐘擺運(yùn)動

鐘擺運(yùn)動的示意圖如下所示,一條繩子系著一個(gè)球懸掛某處,把球拉起一定的角度釋放后,球就會帶動繩子沿著一條圓弧來回運(yùn)動,這條圓弧的半徑就是繩子的長度。

這個(gè)效果通過代碼來實(shí)現(xiàn)的話,需要做下面的事情:
- 繪制頂部的橫線,代表懸掛的頂點(diǎn);
- 繪制運(yùn)動的圓弧路徑,以便讓球沿著圓弧運(yùn)動;
- 繪制實(shí)心圓代表球,并通過動畫控制沿著一條圓弧運(yùn)動;
- 用一條頂端固定,末端指向球心的直線代表繩子;
- 當(dāng)球運(yùn)動到弧線的終點(diǎn)后,通過動畫反轉(zhuǎn)(
reverse)控制球 返回;到起點(diǎn)后再正向(forward) 運(yùn)動就可以實(shí)現(xiàn)來回運(yùn)動的效果了。
具體實(shí)現(xiàn)的代碼如下,這里在繪制球的時(shí)候給 Paint 對象增加了一個(gè) maskFilter 屬性,以便讓球看起來發(fā)光,更加好看點(diǎn)。
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);
}
}總結(jié)
本篇介紹了三種 Loading 動效的繪制邏輯和實(shí)現(xiàn)代碼,可以看到利用路徑屬性進(jìn)行繪圖以及動畫控制可以實(shí)現(xiàn)很多有趣的動畫效果。
以上就是Android Flutter繪制有趣的 loading加載動畫的詳細(xì)內(nèi)容,更多關(guān)于Android Flutter加載動畫的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
實(shí)現(xiàn)一個(gè)Android鎖屏App功能的難點(diǎn)總結(jié)
這篇文章主要介紹了實(shí)現(xiàn)一個(gè)Android鎖屏App功能的難點(diǎn)總結(jié),可以有效的解決鎖屏開發(fā)的問題,有需要的可以參考一下。2016-11-11
Android 將 android view 的位置設(shè)為右下角的解決方法
Android 將 android view 的位置設(shè)為右下角的解決方法,需要的朋友可以參考一下2013-05-05
Android xml文件的序列化實(shí)現(xiàn)代碼
Android提供了XmlSerializer來實(shí)現(xiàn)XML文件的序列化。相比傳統(tǒng)方式,更高效安全,需要的朋友可以參考下2014-02-02
android利用ContentResolver訪問者獲取手機(jī)短信信息
本篇文章主要介紹了android利用ContentResolver訪問者獲取手機(jī)短信信息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02
Android 將view 轉(zhuǎn)換為Bitmap出現(xiàn)空指針問題解決辦法
這篇文章主要介紹了Android 將view 轉(zhuǎn)換為Bitmap出現(xiàn)空指針問題解決辦法的相關(guān)資料,這里提供實(shí)例并提供解決辦法,需要的朋友可以參考下2017-07-07
Android通過自定義view實(shí)現(xiàn)刮刮樂效果詳解
這篇文章主要介紹了如何在Android中利用自定義的view實(shí)現(xiàn)刮刮樂的效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟上小編一起動手試一試2022-03-03
Android開發(fā)之圖形圖像與動畫(四)AnimationListener簡介
就像Button控件有監(jiān)聽器一樣,動畫效果也有監(jiān)聽器,只需要實(shí)現(xiàn)AnimationListener就可以實(shí)現(xiàn)對動畫效果的監(jiān)聽,感興趣的朋友可以了解下啊,希望本文對你有所幫助2013-01-01

