1. 程式人生 > Android入門教學 >Android 進度條 ProgressBar

Android 進度條 ProgressBar

今天要學的是一個特定場合要用到的控制元件——進度條控制元件。進度條的作用不言而喻,而在實際使用中,通常會有兩種型別的進度條:橫向進度條和圓形進度條。當然,ProgressBar 也是支援這兩種型別的,可以應對大多數的開發場景。

1. ProgressBar 的特性

ProgressBar 是一個圖形型別的控制元件,用來展示當前進度,可以是下載、跳轉、切換、儲存等等任何可能比較耗時的任務,它在很多場景下對使用者體驗是有很大幫助的,所以我們千萬不能忽略它,要學會靈活的使用,否則使用者可能會以為傳送了卡頓或者 ANR 從而關閉應用,大大減低使用者體驗。

2. ProgressBar 的屬性

我們先來看看 ProgressBar 的常用屬性:

  • android:max:
    設定 ProgressBar 的最大值,即進度條走完時的總進度。通常和業務相關,比如下載 的時候,那麼 max 就可以設定成下載檔案的大小。預設是 100。
  • android:indeterminate:
    設定是否開啟不確定模式,該屬性是一個 boolean 值。不確定模式就是我們在使用 Android 手機的時候,會有兩種進度條的樣式,一種是一直迴圈轉圈的,還有一種是會跟隨進度改變的。true 表示進度條會展示實際的進度;而 false 表示在載入時會無限迴圈展示 loading 動畫。
  • android:minHeight:
    設定最小高度。
  • android:minWidth:

    設定最小寬度。
  • android:progress:
    設定進度條的當前進度。
  • style:
    設定進度條的樣式,預設情況下,Android 系統會展示一個迴圈轉圈的 loading 樣式,而如果需要設定其他樣式,就要用的 style 屬性,比如通過設定styleandroid:attr/progressBarStyleHorizontal可以設定成橫向進度條的樣式。
  • android:progressDrawable:
    設定進度條對應的 Drawable 物件的樣式
  • android:secondaryProgress:
    設定二級進度條的進度。看過視訊或者聽過音樂的應該都知道,我們會有兩級進度條,一級是播放進度,二級是緩衝進度。

基本上常用的屬性就這麼多,都還比較好理解,這只是添加了一個進度條,如果我們是android:indeterminate模式,那隻需要展示進度條和隱藏即可;但是如果android:indeterminate為 false,在實際使用中我們還需要在程式碼的邏輯裡去實時更新進度條,這就需要配合 Java 的 api 來完成了。

3. ProgressBar 的常用 API

  • getMax():
    返回進度條的最大值,即進度條的總進度,和android:max屬性相通。
  • getProgress():
    查詢當前進度,和android:progress屬性相通。
  • getSecondaryProgress():
    查詢當前的二級進度,和android:secondaryProgress屬性相通。
  • incrementProgressBy(int diff):
    設定當前增長的進度。
  • incrementSecondaryProgressBy(int diff):
    設定當前二級進度增長的值。
  • isIndeterminate():
    查詢當前進度條是否在不確定模式下。
  • setIndeterminate(boolean indeterminate):
    設定進度條是否啟動不確定模式,和android:indeterminate屬性相通。
    以上常用 API 和屬性基本都是掛鉤的,所以我們可以根據業務場景動態的去更新進度條,從而實現進度的展示。

4. ProgressBar 編碼

Ok,我們有了佈局設定以及 API 控制,就可以開始完成一個進度條的開發了,本節將在 Activity 中啟動一個子執行緒,在子執行緒中通過 sleep 300 毫秒來模擬一個耗時任務,並在執行任務的過程中不斷更新進度條。
首先編寫佈局,我們新增一個橫向非不確定進度條展示精確精度和一個圓形不確定進度條不展示確定進度,然後新增一個 TextView 用於展示具體的進度情況,程式碼如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:id="@+id/progressBar_horizontal"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="30dp"
        android:indeterminate="false"
        android:max="100"
        android:minWidth="200dp"
        android:minHeight="50dp"
        android:progress="1" />

    <ProgressBar
        android:id="@+id/progressBar_circle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:minWidth="50dp"
        android:minHeight="50dp" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/progressBar_horizontal"
        android:layout_alignLeft="@+id/progressBar_horizontal" />

</RelativeLayout>

佈局完成效果如下,上方有一個進度為 1 的橫向進度條,中間有一個迴圈轉圈的圓形進度條。目前任務還沒開啟,所以還沒有進度展示,TextView 內容為空。

Progress示例

下面通過 Java 編寫後臺耗時任務,並同步更新進度條:

package com.emercy.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

    private ProgressBar progressBar;
    private int progressStatus = 0;
    private TextView textView;
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressBar = findViewById(R.id.progressBar_horizontal);
        textView = findViewById(R.id.textView);
        new Thread(new Runnable() {
            public void run() {
                while (progressStatus < 100) {
                    progressStatus += 1;
                    handler.post(new Runnable() {
                        public void run() {
                            progressBar.setProgress(progressStatus);
                            textView.setText(progressStatus + "/" + progressBar.getMax());
                        }
                    });
                    try {
                        // sleep 300毫秒模擬耗時任務
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
}

在上面的程式碼中,橫向 ProgressBar 會在每 300 毫秒更新一次進度(進度增加多少可以根據具體場景,比如下載量、儲存量、解析量等等),更新進度通過setProgress()介面完成。另外本節運用了 Handler 去完成更新,因為耗時操作我們通常會放在子執行緒,但是 Android 系統要求不能在子執行緒中進行 UI 操作,所以我們通過 Handler 完成子執行緒到主執行緒的切換(具體的使用方法會在後面 Handler 章節詳細講解,這裡重點關注 ProgressBar 的使用),直到進度條增加為 100,表示任務完成;而另一個進度條會迴圈 loading,此時會一直迴圈播放進度動畫,直到主動關閉,下面是一張程式碼的效果圖:

Progress實時更新

5. 小結

本節學習了進度條控制元件,介紹 PregressBar 的主要屬性及常用 API,完成了一個耗時任務的進度實時更新程式。ProgressBar 主要針對需要執行耗時任務並且阻塞UI的場景,目的是給使用者一個比較好的等待體驗。

當然如果對 UI 要求很高,或者需要很複雜的 loading 動畫的時候,ProgressBar 也許就不盡如人意了。這時候需要通過自定義 View 完全實現一個自己的進度條控制元件,這個大家在學習了自定義控制元件之後就可以輕鬆完成,關於自定義控制元件我們也會在後面的章節陸續學習到,敬請期待!