前言java
基於安卓平臺的加載動畫庫AVLoadingIndicatorView(https://github.com/81813780/AVLoadingIndicatorView),實現了鴻蒙化遷移和重構,代碼已經開源到(https://gitee.com/iscas-ohos/avloading-indicator-view_ohos.git),歡迎各位下載使用並提出寶貴意見! git
背景github
服務器在加載數據的時候有時須要等待一段時間,加載動畫能夠緩解用戶等待過程當中的焦慮情緒,使等待過程變得更加友好、流暢。AVLoadingIndicatorView是一個開源的加載動畫庫,經過動畫庫的調用,能夠實現各類各樣的加載效果。canvas
組件功能展現api
1. 動畫效果服務器
在原Android版本中,本組件庫裏共有28個加載動畫,鴻蒙版本的組件庫成功實現其中21種動畫效果。因爲鴻蒙系統部分API功能缺失,目前有7個動畫效果未成功遷移。ide
圖1 AVLoadingIndicatorView效果示意圖函數
圖1所示爲鴻蒙平臺的AVLoadingIndicatorView的動畫效果展現,可分爲6行4列,動畫效果的對應名稱(從左至右)以下:oop
Row 1post
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. 動畫控制效果
AVLoadingIndicatorView組件支持對各加載動畫的效果進行控制,控制類型分爲4種:動畫啓動、動畫中止、動畫顯示和動畫隱藏。動畫啓動和動畫中止相互關聯,兩者用於控制動畫是否運行;動畫顯示和動畫隱藏相互關聯,兩者用於控制動畫是否出現,控制效果如圖2所示。
圖2 四種效果控制示意圖
Sample解析
本組件庫中的每一個動畫都有啓動、中止、隱藏和顯示四種控制效果。爲了方便調試和演示,Sample中將全部動畫的對象放入同一個list,經過四個不一樣的按鈕,控制全部動畫同時啓動、中止、隱藏和顯示,效果如圖2所示。
下面介紹控制全部動畫同時啓動、中止、隱藏和顯示的步驟:
一、導入AVLoadingIndicatorView類
import com.wang.avi.AVLoadingIndicatorView;
二、動畫添加到Layout
此處須要將全部動畫添加到Layout中,並將各動畫的對象放入同一list(即代碼中的animatorList)。
//以BallPulseIndicator爲例 myLayout.addComponent(ballPulseIndicator);//BallPulseIndicator添加到Layout animatorList.add(ballPulseIndicator);//BallPulseIndicator對象放入list
//以BallGridPulseIndicator爲例 myLayout.addComponent(ballGridPulseIndicator); animatorList.add(ballGridPulseIndicator);
三、設置四個按鈕,用以控制全部動畫同時啓動、中止、隱藏和顯示。
以"啓動"效果爲例,startBtn按鈕設置了Click監聽,按下按鈕時,會執行startAllAnimator ()方法,startAllAnimator ()方法中藉助for循環,遍歷animatorList中的每個動畫的對象,並調用每一個對象的start()方法,達到動畫啓動的效果。
//按鈕監聽 startBtn.setClickedListener(component-> startAllAnimator(animatorList));//啓動 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();//啓動 } }
//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. 功能實現
每一個動畫效果的繪製都須要執行初始化設置、添加繪畫任務、建立動畫三個步驟,下面以BallPulseIndicator爲例對這三個步驟進行詳細介紹。
(1) 初始化設置 聲明setPaint(),setBound(),draw()方法。
public BallPulseIndicator(Context context) { super(context); Component.DrawTask task = (component, canvas) -> { setPaint();//設置畫筆 setBound();//設置動畫邊界 draw(canvas,getPaint());//內容繪製 }; addDrawTask(task); }
(2) 動畫繪製 用draw()方法在畫布上繪製動畫樣式。
因爲BallPulseIndicator動畫主體是三個圓,第2、第三個圓均是由前一個圓平移獲得,所以要設置每兩個圓之間的距離,圓的半徑大小等屬性。
public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; //設置圓之間距離 float radius=(Math.min(getWidth(),getHeight())-circleSpacing*2)/6; //設置圓的半徑大小 float x = getWidth()/ 2-(radius*2+circleSpacing);//圓心的x軸座標 float y=getHeight() / 2;//圓心的y軸座標 for (int i = 0; i < 3; i++) { canvas.save(); float translateX=x+(radius*2)*i+circleSpacing*i;//平移後新圓心的x軸座標 canvas.translate(translateX, y); canvas.scale(scaleFloats[i], scaleFloats[i]);//縮放效果繪製 canvas.drawCircle(0, 0, radius, paint);//繪製圓 canvas.restore(); } }
(3) 動畫參數設置
經過AnimatorValue對動畫參數進行具體設置,包括動畫的持續時間、重複次數、啓動延遲時間、縮放和旋轉等(BallPulseIndicator只涉及縮放而無旋轉)。
public ArrayList<AnimatorValue> onCreateAnimators() { ArrayList<AnimatorValue> animators=new ArrayList<>(); int[] delays=new int[]{120,240,360}; //設置三個圓的延遲時間 for (int i = 0; i < 3; i++) { final int index=i; AnimatorValue scaleAnim=new AnimatorValue(); //值動畫 scaleAnim.setDuration(750); //動畫持續時間 scaleAnim.setLoopedCount(-1); //動畫無限次重複 scaleAnim.setDelay(delays[i]); //每一個圓的延遲時間 addUpdateListener(scaleAnim, (animatorValue, v) -> { scaleFloats[index] = v;//控制縮放 invalidate();//刷新界面 }); animators.add(scaleAnim); } return animators; }
2. 移植方法
(1) API直接替換
在安卓中使用ValueAnimator類設置加載動畫的屬性,移植以後這些功能主要基於鴻蒙的AnimatorValue類實現。這兩個類中的方法名也不一樣,在進行鴻蒙化遷移時須要根據功能逐一替換。例如:鴻蒙中使用setLoopedCount()方法替換原setRepeatCount()方法來實現動畫重複次數的設置。
(2) 函數重寫
鴻蒙的AnimatorValue類相比較於安卓,缺乏不少接口,若在實現部分複雜動畫時,須要調用這些接口,只能採用函數重寫的方法,這也是移植中的主要難點。如安卓中用ValueAnimator.ofFloat(1,0.5f,1)來設置動畫的屬性值1—0.5f—1的兩次變化,實現動畫的運行效果,而鴻蒙中缺乏該接口,屬性值只能在0—1之間單次變化,沒法實現動畫的完美效果,須要進行功能重寫,下面給出此功能重寫的代碼。
public void onUpdate(AnimatorValue animatorValue, float v) { if(v<=0.5f) scaleFloats[index] =1-v; else scaleFloats[index] = v; invalidate(); }
文章後續內容和相關附件能夠點擊下面的原文連接前往學習
原文連接:https://harmonyos.51cto.com/posts/2928#bkwz