進度條 ProgressBar
今天要學的是一個特定場合要用到的控件——進度條控件。進度條的作用不言而喻,而在實際使用中,通常會有兩種類型的進度條:橫向進度條和圓形進度條。當然,ProgressBar 也是支持這兩種類型的,可以應(yīng)對大多數(shù)的開發(fā)場景。
1. ProgressBar 的特性
ProgressBar 是一個圖形類型的控件,用來展示當前進度,可以是下載、跳轉(zhuǎn)、切換、保存等等任何可能比較耗時的任務(wù),它在很多場景下對用戶體驗是有很大幫助的,所以我們千萬不能忽略它,要學會靈活的使用,否則用戶可能會以為發(fā)送了卡頓或者 ANR 從而關(guān)閉應(yīng)用,大大減低用戶體驗。
2. ProgressBar 的屬性
我們先來看看 ProgressBar 的常用屬性:
- android:max:
設(shè)置 ProgressBar 的最大值,即進度條走完時的總進度。通常和業(yè)務(wù)相關(guān),比如下載 的時候,那么 max 就可以設(shè)置成下載文件的大小。默認是 100。 - android:indeterminate:
設(shè)置是否開啟不確定模式,該屬性是一個 boolean 值。不確定模式就是我們在使用 Android 手機的時候,會有兩種進度條的樣式,一種是一直循環(huán)轉(zhuǎn)圈的,還有一種是會跟隨進度改變的。true 表示進度條會展示實際的進度;而 false 表示在加載時會無限循環(huán)展示 loading 動畫。 - android:minHeight:
設(shè)置最小高度。 - android:minWidth:
設(shè)置最小寬度。 - android:progress:
設(shè)置進度條的當前進度。 - style:
設(shè)置進度條的樣式,默認情況下,Android 系統(tǒng)會展示一個循環(huán)轉(zhuǎn)圈的 loading 樣式,而如果需要設(shè)置其他樣式,就要用的 style 屬性,比如通過設(shè)置style
為android:attr/progressBarStyleHorizontal
可以設(shè)置成橫向進度條的樣式。 - android:progressDrawable:
設(shè)置進度條對應(yīng)的 Drawable 對象的樣式 - android:secondaryProgress:
設(shè)置二級進度條的進度。看過視頻或者聽過音樂的應(yīng)該都知道,我們會有兩級進度條,一級是播放進度,二級是緩沖進度。
基本上常用的屬性就這么多,都還比較好理解,這只是添加了一個進度條,如果我們是android:indeterminate
模式,那只需要展示進度條和隱藏即可;但是如果android:indeterminate
為 false,在實際使用中我們還需要在代碼的邏輯里去實時更新進度條,這就需要配合 Java 的 api 來完成了。
3. ProgressBar 的常用 API
- getMax():
返回進度條的最大值,即進度條的總進度,和android:max
屬性相通。 - getProgress():
查詢當前進度,和android:progress
屬性相通。 - getSecondaryProgress():
查詢當前的二級進度,和android:secondaryProgress
屬性相通。 - incrementProgressBy(int diff):
設(shè)置當前增長的進度。 - incrementSecondaryProgressBy(int diff):
設(shè)置當前二級進度增長的值。 - isIndeterminate():
查詢當前進度條是否在不確定模式下。 - setIndeterminate(boolean indeterminate):
設(shè)置進度條是否啟動不確定模式,和android:indeterminate
屬性相通。
以上常用 API 和屬性基本都是掛鉤的,所以我們可以根據(jù)業(yè)務(wù)場景動態(tài)的去更新進度條,從而實現(xiàn)進度的展示。
4. ProgressBar 編碼
Ok,我們有了布局設(shè)置以及 API 控制,就可以開始完成一個進度條的開發(fā)了,本節(jié)將在 Activity 中啟動一個子線程,在子線程中通過 sleep 300 毫秒來模擬一個耗時任務(wù),并在執(zhí)行任務(wù)的過程中不斷更新進度條。
首先編寫布局,我們添加一個橫向非不確定進度條展示精確精度和一個圓形不確定進度條不展示確定進度,然后添加一個 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 的橫向進度條,中間有一個循環(huán)轉(zhuǎn)圈的圓形進度條。目前任務(wù)還沒開啟,所以還沒有進度展示,TextView 內(nèi)容為空。
下面通過 Java 編寫后臺耗時任務(wù),并同步更新進度條:
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毫秒模擬耗時任務(wù)
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}
在上面的代碼中,橫向 ProgressBar 會在每 300 毫秒更新一次進度(進度增加多少可以根據(jù)具體場景,比如下載量、保存量、解析量等等),更新進度通過setProgress()
接口完成。另外本節(jié)運用了 Handler 去完成更新,因為耗時操作我們通常會放在子線程,但是 Android 系統(tǒng)要求不能在子線程中進行 UI 操作,所以我們通過 Handler 完成子線程到主線程的切換(具體的使用方法會在后面 Handler 章節(jié)詳細講解,這里重點關(guān)注 ProgressBar 的使用),直到進度條增加為 100,表示任務(wù)完成;而另一個進度條會循環(huán) loading,此時會一直循環(huán)播放進度動畫,直到主動關(guān)閉,下面是一張代碼的效果圖:
5. 小結(jié)
本節(jié)學習了進度條控件,介紹 PregressBar 的主要屬性及常用 API,完成了一個耗時任務(wù)的進度實時更新程序。ProgressBar 主要針對需要執(zhí)行耗時任務(wù)并且阻塞UI的場景,目的是給用戶一個比較好的等待體驗。
當然如果對 UI 要求很高,或者需要很復雜的 loading 動畫的時候,ProgressBar 也許就不盡如人意了。這時候需要通過自定義 View 完全實現(xiàn)一個自己的進度條控件,這個大家在學習了自定義控件之后就可以輕松完成,關(guān)于自定義控件我們也會在后面的章節(jié)陸續(xù)學習到,敬請期待!