利用Android封裝一個(gè)有趣的Loading組件
前言
在上一篇普通的加載千篇一律,有趣的 loading 萬里挑一 中,我們介紹了使用Path
類的PathMetrics
屬性來控制繪制點(diǎn)在路徑上運(yùn)動(dòng)來實(shí)現(xiàn)比較有趣的loading
效果。有評(píng)論說因?yàn)槭呛谏尘埃钥粗每?。黑色背景確實(shí)顯得高端一點(diǎn),但是并不是其他配色也不行,本篇我們來封裝一個(gè)可以自定義配置前景色和背景色的Loading
組件。
組件定義
loading
組件共定義4個(gè)入口參數(shù):
- 前景色:繪制圖形的前景色;
- 背景色:繪制圖形的背景色;
- 圖形尺寸:繪制圖形的尺寸;
- 加載文字:可選,如果有文字就顯示,沒有就不顯示。
得到的Loading
組件類如下所示:
class LoadingAnimations extends StatefulWidget { final Color bgColor; final Color foregroundColor; String? loadingText; final double size; LoadingAnimations( {required this.foregroundColor, required this.bgColor, this.loadingText, this.size = 100.0, Key? key}) : super(key: key); @override _LoadingAnimationsState createState() => _LoadingAnimationsState(); }
圓形Loading
我們先來實(shí)現(xiàn)一個(gè)圓形的loading
,效果如下所示。
這里繪制了兩組沿著一個(gè)大圓運(yùn)動(dòng)的軸對(duì)稱的實(shí)心圓,半徑依次減小,圓心間距隨著動(dòng)畫時(shí)間逐步拉大。實(shí)際上實(shí)現(xiàn)的核心還是基于Path
的PathMetrics
。具體實(shí)現(xiàn)代碼如下:
_drawCircleLoadingAnimaion( Canvas canvas, Size size, Offset center, Paint paint) { final radius = boxSize / 2; final ballCount = 6; final ballRadius = boxSize / 15; var circlePath = Path() ..addOval(Rect.fromCircle(center: center, radius: radius)); var circleMetrics = circlePath.computeMetrics(); for (var pathMetric in circleMetrics) { for (var i = 0; i < ballCount; ++i) { var lengthRatio = animationValue * (1 - i / ballCount); var tangent = pathMetric.getTangentForOffset(pathMetric.length * lengthRatio); var ballPosition = tangent!.position; canvas.drawCircle(ballPosition, ballRadius / (1 + i), paint); canvas.drawCircle( Offset(size.width - tangent.position.dx, size.height - tangent.position.dy), ballRadius / (1 + i), paint); } } }
其中路徑比例為lengthRatio
,通過animationValue
乘以一個(gè)系數(shù)使得實(shí)心圓的間距越來越大 ,同時(shí)通過Offset(size.width - tangent.position.dx, size.height - tangent.position.dy)
繪制了一組對(duì)對(duì)稱的實(shí)心圓,這樣整體就有一個(gè)圓形的效果了,動(dòng)起來也會(huì)更有趣一點(diǎn)。
橢圓運(yùn)動(dòng)Loading
橢圓和圓形沒什么區(qū)別,這里我們搞個(gè)漸變的效果看看,利用之前介紹過的Paint
的shader
可以實(shí)現(xiàn)漸變色繪制效果。
實(shí)現(xiàn)代碼如下所示。
final ballCount = 6; final ballRadius = boxSize / 15; var ovalPath = Path() ..addOval(Rect.fromCenter( center: center, width: boxSize, height: boxSize / 1.5)); paint.shader = LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [this.foregroundColor, this.bgColor], ).createShader(Offset.zero & size); var ovalMetrics = ovalPath.computeMetrics(); for (var pathMetric in ovalMetrics) { for (var i = 0; i < ballCount; ++i) { var lengthRatio = animationValue * (1 - i / ballCount); var tangent = pathMetric.getTangentForOffset(pathMetric.length * lengthRatio); var ballPosition = tangent!.position; canvas.drawCircle(ballPosition, ballRadius / (1 + i), paint); canvas.drawCircle( Offset(size.width - tangent.position.dx, size.height - tangent.position.dy), ballRadius / (1 + i), paint); } }
當(dāng)然,如果漸變色的顏色更豐富一點(diǎn)會(huì)更有趣些。
貝塞爾曲線Loading
通過貝塞爾曲線構(gòu)建一條Path
,讓一組圓形沿著貝塞爾曲線運(yùn)動(dòng)的Loading
效果也很有趣。
原理和圓形的一樣,首先是構(gòu)建貝塞爾曲線Path
,代碼如下。
var bezierPath = Path() ..moveTo(size.width / 2 - boxSize / 2, center.dy) ..quadraticBezierTo(size.width / 2 - boxSize / 4, center.dy - boxSize / 4, size.width / 2, center.dy) ..quadraticBezierTo(size.width / 2 + boxSize / 4, center.dy + boxSize / 4, size.width / 2 + boxSize / 2, center.dy) ..quadraticBezierTo(size.width / 2 + boxSize / 4, center.dy - boxSize / 4, size.width / 2, center.dy) ..quadraticBezierTo(size.width / 2 - boxSize / 4, center.dy + boxSize / 4, size.width / 2 - boxSize / 2, center.dy);
這里實(shí)際是構(gòu)建了兩條貝塞爾曲線,先從左邊到右邊,然后再折回來。之后就是運(yùn)動(dòng)的實(shí)心圓了,這個(gè)只是數(shù)量上多了,ballCount
為30
,這樣效果看著就有一種拖影的效果。
var ovalMetrics = bezierPath.computeMetrics(); for (var pathMetric in ovalMetrics) { for (var i = 0; i < ballCount; ++i) { var lengthRatio = animationValue * (1 - i / ballCount); var tangent = pathMetric.getTangentForOffset(pathMetric.length * lengthRatio); var ballPosition = tangent!.position; canvas.drawCircle(ballPosition, ballRadius / (1 + i), paint); canvas.drawCircle( Offset(size.width - tangent.position.dx, size.height - tangent.position.dy), ballRadius / (1 + i), paint); } }
這里還可以改變運(yùn)動(dòng)方向,實(shí)現(xiàn)一些其他的效果,例如下面的效果,第二組圓球的繪制位置實(shí)際上是第一組圓球的x、y坐標(biāo)的互換。
var lengthRatio = animationValue * (1 - i / ballCount); var tangent = pathMetric.getTangentForOffset(pathMetric.length * lengthRatio); var ballPosition = tangent!.position; canvas.drawCircle(ballPosition, ballRadius / (1 + i), paint); canvas.drawCircle(Offset(tangent.position.dy, tangent.position.dx), ballRadius / (1 + i), paint);
組件使用
我們來看如何使用我們定義的這個(gè)組件,使用代碼如下,我們用Future延遲模擬了一個(gè)加載效果,在加載過程中使用loading
指示加載過程,加載完成后顯示圖片。
class _LoadingDemoState extends State<LoadingDemo> { var loaded = false; @override void initState() { super.initState(); Future.delayed(Duration(seconds: 5), () { setState(() { loaded = true; }); }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: Text('Loading 使用'), ), body: Center( child: loaded ? Image.asset( 'images/beauty.jpeg', width: 100.0, ) : LoadingAnimations( foregroundColor: Colors.blue, bgColor: Colors.white, size: 100.0, ), ), ); }
最終運(yùn)行的效果如下,源碼已提交至:繪圖相關(guān)源碼,文件名為loading_animations.dart
。
總結(jié)
本篇介紹了Loading
組件的封裝方法,核心要點(diǎn)還是利用Path
和動(dòng)畫控制繪制元素的運(yùn)動(dòng)軌跡來實(shí)現(xiàn)更有趣的效果。在實(shí)際應(yīng)用過程中,也可以根據(jù)交互設(shè)計(jì)的需要,做一些其他有趣的加載動(dòng)效,提高等待過程的趣味性。
到此這篇關(guān)于利用Android封裝一個(gè)有趣的Loading組件的文章就介紹到這了,更多相關(guān)Android封裝Loading組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 自動(dòng)化測(cè)試經(jīng)驗(yàn)分享 深入U(xiǎn)iScrollable
UiScrollable是一個(gè)UiCollection(這東西還沒搞懂),我們可以使用它,在可滑動(dòng)的頁面(水平滑動(dòng)或上下滑動(dòng)都可以)上查找我們想要的控件(item)2013-05-05Android利用startActivityForResult返回?cái)?shù)據(jù)到前一個(gè)Activity
這篇文章主要介紹了Android利用startActivityForResult返回?cái)?shù)據(jù)到前一個(gè)Activity,幫助大家更好的利用Android進(jìn)行開發(fā),感興趣的朋友可以了解下2021-01-01Android實(shí)現(xiàn)ListView異步加載圖片的方法
這篇文章主要介紹了Android實(shí)現(xiàn)ListView異步加載圖片的方法,以實(shí)例形式較為詳細(xì)的分析了Android中ListView異步加載圖片的原理與相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10Android使用MediaRecorder實(shí)現(xiàn)錄音及播放
這篇文章主要為大家詳細(xì)介紹了Android使用MediaRecorder實(shí)現(xiàn)錄音及播放,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02詳解Android Studio如何導(dǎo)入第三方類庫、jar包和so庫
這篇文章主要介紹了Android Studio如何導(dǎo)入第三方類庫、jar包和so庫的相關(guān)資料,需要的朋友可以參考下2017-06-06Android?studio?利用共享存儲(chǔ)進(jìn)行用戶的注冊(cè)和登錄驗(yàn)證功能
這篇文章主要介紹了Android?studio?利用共享存儲(chǔ)進(jìn)行用戶的注冊(cè)和登錄驗(yàn)證功能,包括注冊(cè)頁面布局及登錄頁面功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12android中圖片加載到內(nèi)存的實(shí)例代碼
這篇文章主要介紹了android中圖片加載到內(nèi)存的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09Flutter實(shí)現(xiàn)心動(dòng)的動(dòng)畫特效
為了追求更好的用戶體驗(yàn),有時(shí)候我們需要一個(gè)類似心跳一樣跳動(dòng)著的控件來吸引用戶的注意力。本文將利用Flutter實(shí)現(xiàn)這一動(dòng)畫特效,需要的可以參考一下2022-04-04自己實(shí)現(xiàn)的android樹控件treeview
在項(xiàng)目中經(jīng)常需要一個(gè)需要一個(gè)樹狀框架,因?yàn)橐恍┰驔]有使用系統(tǒng)自帶的控件,所以就自己寫了一個(gè),現(xiàn)在分享給大家2014-01-01Android 滑動(dòng)Scrollview標(biāo)題欄漸變效果(仿京東toolbar)
這篇文章主要介紹了Android 滑動(dòng)Scrollview標(biāo)題欄漸變效果(仿京東toolbar),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01