鴻蒙開源第三方元件——進度輪ProgressWheel

前言

基於安卓平臺的進度輪元件ProgressWheel(https://github。com/Alford087/ProgressWheel),實現了鴻蒙化遷移和重構,程式碼已經開源到(https://gitee。com/isrc_ohos/progress-wheel_ohos),歡迎各位下載使用並提出寶貴意見!

背景

進度輪是UI介面中常見的元件,通常用於向用戶顯示某個耗時操作完成的百分比,例如:載入狀態、下載進度、重新整理網頁等。進度輪可以動態地顯示操作進度,避免使用者誤以為程式失去響應,從而更好地提高使用者介面的友好性。

元件功能展示

基於鴻蒙系統,透過自定義控制元件屬性的方式實現了進度輪元件,該元件支援進度輪的旋轉、進度增加兩種功能。

1、旋轉

點選“Start spinning”按鈕,此時進度輪會開始旋轉,在旋轉過程中按鈕上的“Start spinning”變成“Stop spinning”,點選“Stop spinning”使用者可以隨時停止旋轉,效果如圖1所示。進度輪旋轉功能主要用於展示伺服器正在載入資料的狀態,此時的作用和載入動畫庫AVLoadingIndicatorView類似。

鴻蒙開源第三方元件——進度輪ProgressWheel

圖1 進度輪旋轉

2、進度增加

點選“Increment”按鈕,進度輪會定量增加進度,進度值會實時顯示在進度輪的中間,效果如圖2所示,進度增加功能主要用於展示伺服器載入資料的進度。

鴻蒙開源第三方元件——進度輪ProgressWheel

圖2 按鈕控制進度增加

Sample解析

在Sample中向用戶提供了5個場景,分別是:(1)進度輪旋轉、(2)按鈕控制進度增加、(3)原生進度條控制進度增加、(4)背景改變、(5)樣式改變。其中(1)、(2)兩種場景較為簡單,均為按鈕觸發,呼叫ProgressWheel類的開始旋轉、進度增加方法即可,在Library解析部分會詳細解釋。此處重點介紹(3)、(4)、(5)三種場景。

1、原生進度條控制進度增加

鴻蒙開源第三方元件——進度輪ProgressWheel

圖3 原生進度條控制進度增加

原生進度條是指鴻蒙系統的基本元件slider,它也可以用於顯示內容載入或操作處理的進度,此處我們透過拖動原生進度條來改變進度輪的進度值,並將進度值實時顯示。效果如圖3所示,程式碼實現如下:

@Overridepublic void onProgressUpdated(Slider seekBar, int i, boolean b){    //原生進度條和進度輪換算,100代表原生進度條的進度最大值,360代表進度輪的進度最大值    double progress = 360。0 * (seekBar。getProgress() / 100。0); //進度輪進度設定 wheel。setProgress((int) progress);}

2、背景改變

鴻蒙開源第三方元件——進度輪ProgressWheel

使用Random 類產生隨機數,特定處理後作為背景畫素點。點選“Random bg”按鈕,背景畫素點顯示,進度輪的背景會發生隨機變化。效果如圖4所示。程式碼如下:

//背景改變private static void randomBg(ProgressWheel wheel) {    //隨機產生背景元素    Random random = new Random();    int firstColour = random。nextInt();//隨機數獲取    int secondColour = random。nextInt();    int patternSize = (1 + random。nextInt(3)) * 8;//隨機數處理    int patternChange = (1 + random。nextInt(3)) * 8;    int[] pixels = new int[patternSize];    for (int i = 0; i < patternSize; i++) {        pixels[i] = (i > patternChange) ? firstColour : secondColour;//得到畫素點    }    PixelMap。InitializationOptions options=new PixelMap。InitializationOptions();    options。size=new Size(1,patternSize);    options。pixelFormat=PixelFormat。ARGB_8888;    //設定背景元素    wheel。setRimShader(new PixelMapShader(            new PixelMapHolder(PixelMap。create(pixels, options)),            Shader。TileMode。REPEAT_TILEMODE,            Shader。TileMode。REPEAT_TILEMODE), Paint。ShaderType。RADIAL_SHADER);}

3、樣式改變

鴻蒙開源第三方元件——進度輪ProgressWheel

圖5 進度輪樣式改變

透過自定義進度輪的長度、寬度、背景等來設計不同的樣式,點選“A different style”按鈕觸發樣式改變,效果如圖5所示,程式碼如下:

//樣式改變private static void styleRandom(ProgressWheel wheel, Context ctx) {    wheel。setRimShader(null, Paint。ShaderType。RADIAL_SHADER);    wheel。setRimColor(0xFFFFFFFF);    wheel。setCircleColor(0x00000000);//內圓顏色    wheel。setBarColor(0xFF000000);//進度輪體顏色    wheel。setContourColor(0xFFFFFFFF);//外圓顏色    wheel。setBarWidth(pxFromDp(ctx, 8));//寬度    wheel。setBarLength(pxFromDp(ctx, 100));//長度    wheel。setSpinSpeed(2);//旋轉速度    wheel。setDelayMillis(3);//間隔時間}

Library解析

1。功能實現

(1)進度輪繪製。

該功能是透過ProgressWheel類來實現的,在該類中首先宣告setupBounds()、setupPaints()方法,後使用canvas繪製進度輪,設定內圓、外圓、條紋等、文字等屬性。文字用於顯示進度輪的屬性值,不侷限於顯示當前進度。

public ProgressWheel(Context context) { super(context); DrawTask task = (component, canvas) -> { //初始化元素邊界 setupBounds(); //初始化繪製屬性 setupPaints(); //繪製內圓 canvas。drawArc(innerCircleBounds, new Arc(360, 360, false), circlePaint); //繪製外圓 canvas。drawArc(circleBounds, new Arc(360, 360, false), rimPaint); canvas。drawArc(circleOuterContour, new Arc(360, 360, false), contourPaint); //繪製條紋 if (isSpinning) { canvas。drawArc(circleBounds, new Arc(progress - 90, barLength, false), barPaint); } else { canvas。drawArc(circleBounds, new Arc(-90, progress, false), barPaint); } //設定文字於圓心處顯示 float textHeight = textPaint。descent() - textPaint。ascent(); float verticalTextOffset = (textHeight / 2) - textPaint。descent(); for (String line : splitText) { float horizontalTextOffset = textPaint。measureText(line) / 2; canvas。drawText( textPaint, line, (float) component。getWidth() / 2 - horizontalTextOffset, (float) component。getHeight() / 2 + verticalTextOffset); } //旋轉時在不同的位置畫進度條 if (isSpinning) { scheduleRedraw(); } }; addDrawTask(task);}

(2)進度輪旋轉

該功能只提供給使用者進度輪旋轉的展示形式,不提供當前執行緒的量化進度。

1)開始旋轉。進度輪進入旋轉模式時,需要開闢新的執行緒,每隔一定時間重新繪製進度,來達到旋轉的效果。

public void startSpinning() { isSpinning = true;//設定當前為旋轉狀態 pinHandler。sendEvent(0);//更新進度}

2)停止旋轉。進度輪停止旋轉時,進度值被置零。

public void stopSpinning() { isSpinning = false;//設定當前為停止狀態 progress = 0;//進度清零 invalidate();}

(3)進度增加

該功能需提前設定好增量,每次增加固定的進度,進度的最大值設定為360,當超過最大值時,進度值被置零。該模式在旋轉時提供當前的量化進度資料,使用者可以清晰地瞭解當前的執行緒進度,是一種對使用者更友好的互動模式。

public void incrementProgress(int amount) { isSpinning = false;//增加進度時進度輪不旋轉 progress+= amount;//定量增加 if (progress > 360){ progress %= 360;//超過360會自動重置 } invalidate();}

2。移植方法

本元件在移植時大部分採用API替換的方法,少數方法需要重寫,如處理進度輪旋轉的時候重寫spinHandler()方法,該方法的功能是:進度輪旋轉時在不同的畫素位置繪製進度條,移動的位置超過360度則置為0度,重新旋轉。程式碼如下:

//每次繪製要移動的畫素數目private float spinSpeed = 2f;//繪製過程的時間間隔private int delayMillis = 100;private EventHandler spinHandler = new EventHandler(EventRunner。getMainEventRunner()){ @Override public void processEvent(InnerEvent msg) { invalidate(); if (isSpinning) { //更新畫進度的位置 progress += spinSpeed; //要移動的畫素數目超過360則重置 if (progress > 360) { progress = 0; } spinHandler。sendEvent(0, delayMillis); } super。processEvent(msg); }};

專案貢獻人

劉磊 鄭森文 朱偉 陳美汝 張馨心