鴻蒙開源第三方組件的遷移-加載動(dòng)畫庫
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz
前言
基于安卓平臺(tái)的加載動(dòng)畫庫AVLoadingIndicatorView(https://github.com/81813780/AVLoadingIndicatorView),實(shí)現(xiàn)了鴻蒙化遷移和重構(gòu),代碼已經(jīng)開源到(https://gitee.com/iscas-ohos/avloading-indicator-view_ohos.git),歡迎各位下載使用并提出寶貴意見!
背景
服務(wù)器在加載數(shù)據(jù)的時(shí)候有時(shí)需要等待一段時(shí)間,加載動(dòng)畫可以緩解用戶等待過程中的焦慮情緒,使等待過程變得更加友好、流暢。AVLoadingIndicatorView是一個(gè)開源的加載動(dòng)畫庫,通過動(dòng)畫庫的調(diào)用,可以實(shí)現(xiàn)各種各樣的加載效果。
組件功能展示
1. 動(dòng)畫效果
在原Android版本中,本組件庫里共有28個(gè)加載動(dòng)畫,鴻蒙版本的組件庫成功實(shí)現(xiàn)其中21種動(dòng)畫效果。由于鴻蒙系統(tǒng)部分API功能缺失,目前有7個(gè)動(dòng)畫效果未成功遷移。

圖1 AVLoadingIndicatorView效果示意圖
圖1所示為鴻蒙平臺(tái)的AVLoadingIndicatorView的動(dòng)畫效果展示,可分為6行4列,動(dòng)畫效果的對(duì)應(yīng)名稱(從左至右)如下:
Row 1 BallPulseIndicator,BallGridPulseIndicator,BallClipRotateIndicator,BallClipRotatePulseIndicator
Row 2 PacmanIndicator,BallClipRotateMultipleIndicator, SemiCircleSpinIndicator,BallRotateIndicator
Row 3 BallScaleIndicator,LineScaleIndicator,LineScalePartyIndicator,BallScaleMultipleIndicator
Row 4 BallPulseSyncIndicator,BallBeatIndicator,LineScalePulseOutIndicator,LineScalePulseOutRapidIndicator
Row 5 BallScaleRippleIndicator,BallScaleRippleMultipleIndicator,BallSpinFadeLoaderIndicator,LineSpinFadeLoaderIndicator
Row 6 BallGridBeatIndicator
2. 動(dòng)畫控制效果
AVLoadingIndicatorView組件支持對(duì)各加載動(dòng)畫的效果進(jìn)行控制,控制類型分為4種:動(dòng)畫啟動(dòng)、動(dòng)畫停止、動(dòng)畫顯示和動(dòng)畫隱藏。動(dòng)畫啟動(dòng)和動(dòng)畫停止相互關(guān)聯(lián),二者用于控制動(dòng)畫是否運(yùn)行;動(dòng)畫顯示和動(dòng)畫隱藏相互關(guān)聯(lián),二者用于控制動(dòng)畫是否出現(xiàn),控制效果如圖2所示。

圖2 四種效果控制示意圖
Sample解析
本組件庫中的每個(gè)動(dòng)畫都有啟動(dòng)、停止、隱藏和顯示四種控制效果。為了方便調(diào)試和演示,Sample中將所有動(dòng)畫的對(duì)象放入同一個(gè)list,通過四個(gè)不同的按鈕,控制所有動(dòng)畫同時(shí)啟動(dòng)、停止、隱藏和顯示,效果如圖2所示。
下面介紹控制所有動(dòng)畫同時(shí)啟動(dòng)、停止、隱藏和顯示的步驟:
1、導(dǎo)入AVLoadingIndicatorView類
- import com.wang.avi.AVLoadingIndicatorView;
2、動(dòng)畫添加到Layout
此處需要將所有動(dòng)畫添加到Layout中,并將各動(dòng)畫的對(duì)象放入同一list(即代碼中的animatorList)。
- //以BallPulseIndicator為例
- myLayout.addComponent(ballPulseIndicator);//BallPulseIndicator添加到Layout
- animatorList.add(ballPulseIndicator);//BallPulseIndicator對(duì)象放入list
- //以BallGridPulseIndicator為例
- myLayout.addComponent(ballGridPulseIndicator);
- animatorList.add(ballGridPulseIndicator);
3、設(shè)置四個(gè)按鈕,用以控制所有動(dòng)畫同時(shí)啟動(dòng)、停止、隱藏和顯示。
以"啟動(dòng)"效果為例,startBtn按鈕設(shè)置了Click監(jiān)聽,按下按鈕時(shí),會(huì)執(zhí)行startAllAnimator ()方法,startAllAnimator ()方法中借助for循環(huán),遍歷animatorList中的每一個(gè)動(dòng)畫的對(duì)象,并調(diào)用每個(gè)對(duì)象的start()方法,達(dá)到動(dòng)畫啟動(dòng)的效果。
- //按鈕監(jiān)聽
- startBtn.setClickedListener(component-> startAllAnimator(animatorList));//啟動(dòng)
- endBtn.setClickedListener(component-> stopAllAnimator(animatorList));//停止
- hideBtn.setClickedListener(component-> hideAllAnimator(animatorList));//隱藏
- showBtn.setClickedListener(component-> showAllAnimator(animatorList));//顯示
- //start
- private void startAllAnimator(ArrayList<AVLoadingIndicatorView> avLoadingIndicatorViews){
- for (int i = 0; i < avLoadingIndicatorViews.size(); i++) {
- avLoadingIndicatorViews.get(i).start();//啟動(dòng)
- }
- }
- //stop
- private void stopAllAnimator(ArrayList<AVLoadingIndicatorView> avLoadingIndicatorViews){
- for (int i = 0; i < avLoadingIndicatorViews.size(); i++) {
- avLoadingIndicatorViews.get(i).stop();//停止
- }
- }
- //hide
- private void hideAllAnimator(ArrayList<AVLoadingIndicatorView> avLoadingIndicatorViews){
- for (int i = 0; i < avLoadingIndicatorViews.size(); i++) {
- avLoadingIndicatorViews.get(i).hide();//隱藏
- }
- }
- //show
- private void showAllAnimator(ArrayList<AVLoadingIndicatorView> avLoadingIndicatorViews){
- for (int i = 0; i < avLoadingIndicatorViews.size(); i++) {
- avLoadingIndicatorViews.get(i).show();//顯示
- }
- }
Library解析
1. 功能實(shí)現(xiàn)
每個(gè)動(dòng)畫效果的繪制都需要執(zhí)行初始化設(shè)置、添加繪畫任務(wù)、創(chuàng)建動(dòng)畫三個(gè)步驟,下面以BallPulseIndicator為例對(duì)這三個(gè)步驟進(jìn)行詳細(xì)介紹。
(1) 初始化設(shè)置 聲明setPaint(),setBound(),draw()方法。
- public BallPulseIndicator(Context context) {
- super(context);
- Component.DrawTask task = (component, canvas) -> {
- setPaint();//設(shè)置畫筆
- setBound();//設(shè)置動(dòng)畫邊界
- draw(canvas,getPaint());//內(nèi)容繪制
- };
- addDrawTask(task);
- }
(2) 動(dòng)畫繪制 用draw()方法在畫布上繪制動(dòng)畫樣式。
由于BallPulseIndicator動(dòng)畫主體是三個(gè)圓,第二、第三個(gè)圓均是由前一個(gè)圓平移得到,因此要設(shè)置每?jī)蓚€(gè)圓之間的距離,圓的半徑大小等屬性。
- public void draw(Canvas canvas, Paint paint) {
- float circleSpacing=4; //設(shè)置圓之間距離
- float radius=(Math.min(getWidth(),getHeight())-circleSpacing*2)/6; //設(shè)置圓的半徑大小
- float x = getWidth()/ 2-(radius*2+circleSpacing);//圓心的x軸坐標(biāo)
- float y=getHeight() / 2;//圓心的y軸坐標(biāo)
- for (int i = 0; i < 3; i++) {
- canvas.save();
- float translateX=x+(radius*2)*i+circleSpacing*i;//平移后新圓心的x軸坐標(biāo)
- canvas.translate(translateX, y);
- canvas.scale(scaleFloats[i], scaleFloats[i]);//縮放效果繪制
- canvas.drawCircle(0, 0, radius, paint);//繪制圓
- canvas.restore();
- }
- }
(3) 動(dòng)畫參數(shù)設(shè)置
通過AnimatorValue對(duì)動(dòng)畫參數(shù)進(jìn)行具體設(shè)置,包括動(dòng)畫的持續(xù)時(shí)間、重復(fù)次數(shù)、啟動(dòng)延遲時(shí)間、縮放和旋轉(zhuǎn)等(BallPulseIndicator只涉及縮放而無旋轉(zhuǎn))。
- public ArrayList<AnimatorValue> onCreateAnimators() {
- ArrayList<AnimatorValue> animators=new ArrayList<>();
- int[] delays=new int[]{120,240,360}; //設(shè)置三個(gè)圓的延遲時(shí)間
- for (int i = 0; i < 3; i++) {
- final int index=i;
- AnimatorValue scaleAnim=new AnimatorValue(); //值動(dòng)畫
- scaleAnim.setDuration(750); //動(dòng)畫持續(xù)時(shí)間
- scaleAnim.setLoopedCount(-1); //動(dòng)畫無限次重復(fù)
- scaleAnim.setDelay(delays[i]); //每個(gè)圓的延遲時(shí)間
- addUpdateListener(scaleAnim, (animatorValue, v) -> {
- scaleFloats[index] = v;//控制縮放
- invalidate();//刷新界面
- });
- animators.add(scaleAnim);
- }
- return animators;
- }
2. 移植方法
(1) API直接替換
在安卓中使用ValueAnimator類設(shè)置加載動(dòng)畫的屬性,移植之后這些功能主要基于鴻蒙的AnimatorValue類實(shí)現(xiàn)。這兩個(gè)類中的方法名也不同,在進(jìn)行鴻蒙化遷移時(shí)需要根據(jù)功能逐一替換。例如:鴻蒙中使用setLoopedCount()方法替換原setRepeatCount()方法來實(shí)現(xiàn)動(dòng)畫重復(fù)次數(shù)的設(shè)置。
(2) 函數(shù)重寫
鴻蒙的AnimatorValue類相比較于安卓,缺少很多接口,若在實(shí)現(xiàn)部分復(fù)雜動(dòng)畫時(shí),需要調(diào)用這些接口,只能采用函數(shù)重寫的方法,這也是移植中的主要難點(diǎn)。如安卓中用ValueAnimator.ofFloat(1,0.5f,1)來設(shè)置動(dòng)畫的屬性值1—0.5f—1的兩次變化,實(shí)現(xiàn)動(dòng)畫的運(yùn)行效果,而鴻蒙中缺少該接口,屬性值只能在0—1之間單次變化,無法實(shí)現(xiàn)動(dòng)畫的完美效果,需要進(jìn)行功能重寫,下面給出此功能重寫的代碼 。
- public void onUpdate(AnimatorValue animatorValue, float v) {
- if(v<=0.5f)
- scaleFloats[index] =1-v;
- else
- scaleFloats[index] = v;
- invalidate();
- }
©著作權(quán)歸作者和HarmonyOS技術(shù)社區(qū)共同所有,如需轉(zhuǎn)載,請(qǐng)注明出處,否則將追究法律責(zé)任。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz