進(jìn)度條 ProgressBar
今天要學(xué)的是一個(gè)特定場(chǎng)合要用到的控件——進(jìn)度條控件。進(jìn)度條的作用不言而喻,而在實(shí)際使用中,通常會(huì)有兩種類(lèi)型的進(jìn)度條:橫向進(jìn)度條和圓形進(jìn)度條。當(dāng)然,ProgressBar 也是支持這兩種類(lèi)型的,可以應(yīng)對(duì)大多數(shù)的開(kāi)發(fā)場(chǎng)景。
1. ProgressBar 的特性
ProgressBar 是一個(gè)圖形類(lèi)型的控件,用來(lái)展示當(dāng)前進(jìn)度,可以是下載、跳轉(zhuǎn)、切換、保存等等任何可能比較耗時(shí)的任務(wù),它在很多場(chǎng)景下對(duì)用戶(hù)體驗(yàn)是有很大幫助的,所以我們千萬(wàn)不能忽略它,要學(xué)會(huì)靈活的使用,否則用戶(hù)可能會(huì)以為發(fā)送了卡頓或者 ANR 從而關(guān)閉應(yīng)用,大大減低用戶(hù)體驗(yàn)。
2. ProgressBar 的屬性
我們先來(lái)看看 ProgressBar 的常用屬性:
- android:max:
設(shè)置 ProgressBar 的最大值,即進(jìn)度條走完時(shí)的總進(jìn)度。通常和業(yè)務(wù)相關(guān),比如下載 的時(shí)候,那么 max 就可以設(shè)置成下載文件的大小。默認(rèn)是 100。 - android:indeterminate:
設(shè)置是否開(kāi)啟不確定模式,該屬性是一個(gè) boolean 值。不確定模式就是我們?cè)谑褂?Android 手機(jī)的時(shí)候,會(huì)有兩種進(jìn)度條的樣式,一種是一直循環(huán)轉(zhuǎn)圈的,還有一種是會(huì)跟隨進(jìn)度改變的。true 表示進(jìn)度條會(huì)展示實(shí)際的進(jìn)度;而 false 表示在加載時(shí)會(huì)無(wú)限循環(huán)展示 loading 動(dòng)畫(huà)。 - android:minHeight:
設(shè)置最小高度。 - android:minWidth:
設(shè)置最小寬度。 - android:progress:
設(shè)置進(jìn)度條的當(dāng)前進(jìn)度。 - style:
設(shè)置進(jìn)度條的樣式,默認(rèn)情況下,Android 系統(tǒng)會(huì)展示一個(gè)循環(huán)轉(zhuǎn)圈的 loading 樣式,而如果需要設(shè)置其他樣式,就要用的 style 屬性,比如通過(guò)設(shè)置style為android:attr/progressBarStyleHorizontal可以設(shè)置成橫向進(jìn)度條的樣式。 - android:progressDrawable:
設(shè)置進(jìn)度條對(duì)應(yīng)的 Drawable 對(duì)象的樣式 - android:secondaryProgress:
設(shè)置二級(jí)進(jìn)度條的進(jìn)度??催^(guò)視頻或者聽(tīng)過(guò)音樂(lè)的應(yīng)該都知道,我們會(huì)有兩級(jí)進(jìn)度條,一級(jí)是播放進(jìn)度,二級(jí)是緩沖進(jìn)度。
基本上常用的屬性就這么多,都還比較好理解,這只是添加了一個(gè)進(jìn)度條,如果我們是android:indeterminate模式,那只需要展示進(jìn)度條和隱藏即可;但是如果android:indeterminate為 false,在實(shí)際使用中我們還需要在代碼的邏輯里去實(shí)時(shí)更新進(jìn)度條,這就需要配合 Java 的 api 來(lái)完成了。
3. ProgressBar 的常用 API
- getMax():
返回進(jìn)度條的最大值,即進(jìn)度條的總進(jìn)度,和android:max屬性相通。 - getProgress():
查詢(xún)當(dāng)前進(jìn)度,和android:progress屬性相通。 - getSecondaryProgress():
查詢(xún)當(dāng)前的二級(jí)進(jìn)度,和android:secondaryProgress屬性相通。 - incrementProgressBy(int diff):
設(shè)置當(dāng)前增長(zhǎng)的進(jìn)度。 - incrementSecondaryProgressBy(int diff):
設(shè)置當(dāng)前二級(jí)進(jìn)度增長(zhǎng)的值。 - isIndeterminate():
查詢(xún)當(dāng)前進(jìn)度條是否在不確定模式下。 - setIndeterminate(boolean indeterminate):
設(shè)置進(jìn)度條是否啟動(dòng)不確定模式,和android:indeterminate屬性相通。
以上常用 API 和屬性基本都是掛鉤的,所以我們可以根據(jù)業(yè)務(wù)場(chǎng)景動(dòng)態(tài)的去更新進(jìn)度條,從而實(shí)現(xiàn)進(jìn)度的展示。
4. ProgressBar 編碼
Ok,我們有了布局設(shè)置以及 API 控制,就可以開(kāi)始完成一個(gè)進(jìn)度條的開(kāi)發(fā)了,本節(jié)將在 Activity 中啟動(dòng)一個(gè)子線(xiàn)程,在子線(xiàn)程中通過(guò) sleep 300 毫秒來(lái)模擬一個(gè)耗時(shí)任務(wù),并在執(zhí)行任務(wù)的過(guò)程中不斷更新進(jìn)度條。
首先編寫(xiě)布局,我們添加一個(gè)橫向非不確定進(jìn)度條展示精確精度和一個(gè)圓形不確定進(jìn)度條不展示確定進(jìn)度,然后添加一個(gè) TextView 用于展示具體的進(jìn)度情況,代碼如下:
<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>
布局完成效果如下,上方有一個(gè)進(jìn)度為 1 的橫向進(jìn)度條,中間有一個(gè)循環(huán)轉(zhuǎn)圈的圓形進(jìn)度條。目前任務(wù)還沒(méi)開(kāi)啟,所以還沒(méi)有進(jìn)度展示,TextView 內(nèi)容為空。

下面通過(guò) Java 編寫(xiě)后臺(tái)耗時(shí)任務(wù),并同步更新進(jìn)度條:
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毫秒模擬耗時(shí)任務(wù)
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}
在上面的代碼中,橫向 ProgressBar 會(huì)在每 300 毫秒更新一次進(jìn)度(進(jìn)度增加多少可以根據(jù)具體場(chǎng)景,比如下載量、保存量、解析量等等),更新進(jìn)度通過(guò)setProgress()接口完成。另外本節(jié)運(yùn)用了 Handler 去完成更新,因?yàn)楹臅r(shí)操作我們通常會(huì)放在子線(xiàn)程,但是 Android 系統(tǒng)要求不能在子線(xiàn)程中進(jìn)行 UI 操作,所以我們通過(guò) Handler 完成子線(xiàn)程到主線(xiàn)程的切換(具體的使用方法會(huì)在后面 Handler 章節(jié)詳細(xì)講解,這里重點(diǎn)關(guān)注 ProgressBar 的使用),直到進(jìn)度條增加為 100,表示任務(wù)完成;而另一個(gè)進(jìn)度條會(huì)循環(huán) loading,此時(shí)會(huì)一直循環(huán)播放進(jìn)度動(dòng)畫(huà),直到主動(dòng)關(guān)閉,下面是一張代碼的效果圖:

5. 小結(jié)
本節(jié)學(xué)習(xí)了進(jìn)度條控件,介紹 PregressBar 的主要屬性及常用 API,完成了一個(gè)耗時(shí)任務(wù)的進(jìn)度實(shí)時(shí)更新程序。ProgressBar 主要針對(duì)需要執(zhí)行耗時(shí)任務(wù)并且阻塞UI的場(chǎng)景,目的是給用戶(hù)一個(gè)比較好的等待體驗(yàn)。
當(dāng)然如果對(duì) UI 要求很高,或者需要很復(fù)雜的 loading 動(dòng)畫(huà)的時(shí)候,ProgressBar 也許就不盡如人意了。這時(shí)候需要通過(guò)自定義 View 完全實(shí)現(xiàn)一個(gè)自己的進(jìn)度條控件,這個(gè)大家在學(xué)習(xí)了自定義控件之后就可以輕松完成,關(guān)于自定義控件我們也會(huì)在后面的章節(jié)陸續(xù)學(xué)習(xí)到,敬請(qǐng)期待!
馬超老師 ·
2025 imooc.com All Rights Reserved |