鴻蒙開源第三方組件-進度輪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類似。
圖1 進度輪旋轉
2、進度增加
點擊“Increment”按鈕,進度輪會定量增加進度,進度值會實時顯示在進度輪的中間,效果如圖2所示,進度增加功能主要用于展示服務器加載數據的進度。
圖2 按鈕控制進度增加
Sample解析
在Sample中向用戶提供了5個場景,分別是:(1)進度輪旋轉、(2)按鈕控制進度增加、(3)原生進度條控制進度增加、(4)背景改變、(5)樣式改變。其中(1)、(2)兩種場景較為簡單,均為按鈕觸發,調用ProgressWheel類的開始旋轉、進度增加方法即可,在Library解析部分會詳解解釋。此處重點介紹(3)、(4)、(5)三種場景。
1、原生進度條控制進度增加
圖3 原生進度條控制進度增加
原生進度條是指鴻蒙系統的基本組件slider,它也可以用于顯示內容加載或操作處理的進度,此處我們通過拖動原生進度條來改變進度輪的進度值,并將進度值實時顯示。效果如圖3所示,代碼實現如下:
- @Override
- public void onProgressUpdated(Slider seekBar, int i, boolean b){
- //原生進度條和進度輪換算,100代表原生進度條的進度最大值,360代表進度輪的進度最大值
- double progress = 360.0 * (seekBar.getProgress() / 100.0);
- //進度輪進度設置
- wheel.setProgress((int) progress);
- }
2、背景改變
圖4 進度輪背景改變
使用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、樣式改變
圖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);
- }
- };
項目貢獻人
劉磊 鄭森文 朱偉 陳美汝 張馨心