最近在用原生的控件和佈局繪製一些界面並使用,雖然這些都是Android基本知識,但是有的時候真的感覺力不從心,感覺有必要對Android常用的控件和佈局做一個系統的瞭解。後續一個月甚至更多的時間都會圍繞這個主題展開,畢竟這裏面還是有不少高級控件的,我也會盡量結合應用深入的進行了解。
今天,我們的主題是ProgressBar,下面看一下官方文檔的部分介紹:用於展示一個操作進度,有兩種模式,確定進度的與不確定進度的,詳情也可以參考指定網站(介紹MD的)。
* A user interface element that indicates the progress of an operation. * Progress bar supports two modes to represent progress: determinate, and indeterminate. For * a visual overview of the difference between determinate and indeterminate progress modes, see * <a href="https://material.io/guidelines/components/progress-activity.html#progress-activity-types-of-indicators">
從上面我們知道,其主要用於展示耗時操作進度的,我們知道,耗時的操作有時候進度我們是確切知道的,比如看視頻,有時候是不確定的,比如加載數據庫數據。所以就有了兩種模式
- 確定進度的
- 非確定進度的
下面我們接着看其官方介紹:
* Progress & activity</a>. * Display progress bars to a user in a non-interruptive way. * Show the progress bar in your app's user interface or in a notification * instead of within a dialog. * </p> * <h3>Indeterminate Progress</h3> * <p> * Use indeterminate mode for the progress bar when you do not know how long an * operation will take. * Indeterminate mode is the default for progress bar and shows a cyclic animation without a * specific amount of progress indicated.
* <h3>Determinate Progress</h3> * <p> * Use determinate mode for the progress bar when you want to show that a specific quantity of * progress has occurred. * For example, the percent remaining of a file being retrieved, the amount records in * a batch written to database, or the percent remaining of an audio file that is playing.
這種進度條是不可打斷的,通常建議在用戶接口或者通知中使用而不要在dialog中使用。後面就是對上面兩種模式的詳細介紹了。下面是介紹如何使用的:
* To indicate determinate progress, you set the style of the progress bar to * {@link android.R.style#Widget_ProgressBar_Horizontal} and set the amount of progress. * The following example shows a determinate progress bar that is 25% complete: * <pre> * <ProgressBar * android:id="@+id/determinateBar" * style="@android:style/Widget.ProgressBar.Horizontal" * android:layout_width="wrap_content" * android:layout_height="wrap_content" * android:progress="25"/> * </pre> * You can update the percentage of progress displayed by using the * {@link #setProgress(int)} method, or by calling * {@link #incrementProgressBy(int)} to increase the current progress completed * by a specified amount. * By default, the progress bar is full when the progress value reaches 100. * You can adjust this default by setting the * {@link android.R.styleable#ProgressBar_max android:max} attribute.
我們如何想使用上面介紹的第二種模式,需要使用特定的style;默認的進度條最大值爲100,我們也可以通過屬性或者接口進行設置。
上面的介紹看完了,我們來看看具體的使用,我們可以直接在佈局文件中添加一個ProgressBar控件,運行代碼的結果如下:
<ProgressBar
android:id="@+id/normal_progress_bar_horizon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
這種方式我們平時也會在各種需要加載的場景中遇到,其實它是有很多種style的,
* <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li> * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li> * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li> * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li> * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse * Widget.ProgressBar.Small.Inverse}</li>
其中,第一個主要用於第二種確定進度模式的進度條
{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}
當我們把style設置成種模式的時候,
<ProgressBar
android:id="@+id/normal_progress_bar_default"
android:layout_width="60dp"
android:layout_height="60dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
/>
就是一個靜止的狀態,因爲progress始終是0,需要我們配合具體的業務獲取到特定的進度值來設置從而進行動態的顯示:下面就來看看一個實現好的效果圖:
但是這種樣式的進度條還是蠻醜的,下面我們就來看看如何改變它的展示樣式,在這個控件裏面,有一個android:progressDrawable屬性就是用來設置我們自定義的Drawable圖像的,
<ProgressBar
android:id="@+id/normal_progress_bar_horizon"
style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
android:progressDrawable="@drawable/progress_bar_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:max="100"
android:visibility="invisible" />
自定義的Drawable也很簡單,主要是通過<layer-list>標籤實現:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<corners android:radius="12dp" />
<solid android:color="#1E90DD" />
<stroke android:width="5dp" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="12dp" />
<solid android:color="#00CCEA" />
<stroke android:width="5dp" />
</shape>
</clip>
</item>
</layer-list>
其實,在實際的使用中,我們還有一個很常見的場景,比如看一部電影,播放器會提前預加載,這樣就會產生兩個進度值,一個是播放的進度,一個是預加載的進度。面對這種情況,顯然,ProgressBar是做了處理的,我們可以通過它的android:secondaryProgress屬性進行設置,通常,我們都是通過API結合具體進度值進行操作。下面就來看看其具體的使用和效果:
還是一樣,這個view的樣式不太好看,我們再來自定義一波,步驟和方法和上面一模一樣,但是這裏有三層,一個背景層,一個預加載層,一個播放進度層,所以我們的自定義Drawable如下:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<stroke android:width="5dp" />
<solid android:color=" #DEDEDE" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="5dip" />
<solid android:color="#C2C2C2" />
<stroke android:width="5dp" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<solid android:color="#87CEFA" />
<stroke android:width="5dp" />
</shape>
</clip>
</item>
</layer-list>
運行的結果如下:
關於ProgressBar的介紹,這裏更多的是強調如何使用,理論的東西介紹的就少一些,下面我就把上面運行示例的源碼在這裏簡單的貼一下,有興趣的朋友可以看一下:
package aoto.com.commonwidgetandlayout.basic_widget.progressBar;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
import aoto.com.commonwidgetandlayout.R;
/**
* @author why
* @date 2019-5-20 21:15:46
*/
public class ProgressBarActivity extends AppCompatActivity implements View.OnClickListener {
int progress = 0;
int cacheProgress = 0;
ProgressBar defaultBar1;
ProgressBar horizonBar1;
ProgressBar horizonBar2;
TextView progressText;
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
horizonBar1.setProgress(progress);
if (progress == 100) {
progressText.setText("下載完成");
} else {
progressText.setText("下載進度 " + progress + "%");
}
break;
case 1:
horizonBar2.setProgress(progress);
if(progress==100){
progressText.setText("播放完畢");
}
else {
if(cacheProgress<=100){
progressText.setText("播放完成:"+progress+"%"+",緩存完成"+cacheProgress+"%");
horizonBar2.setSecondaryProgress(cacheProgress);
}
else {
progressText.setText("播放完成:"+progress+"%"+",緩存結束");
}
}
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progress_bar);
findView();
}
private void findView() {
defaultBar1 = findViewById(R.id.normal_progress_bar_default);
horizonBar1 = findViewById(R.id.normal_progress_bar_horizon);
horizonBar2 = findViewById(R.id.normal_progress_bar_horizon2);
progressText = findViewById(R.id.progress_text);
findViewById(R.id.normal_default_bar).setOnClickListener(this);
findViewById(R.id.normal_horizon_bar1).setOnClickListener(this);
findViewById(R.id.normal_horizon_bar2).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.normal_default_bar:
progressText.setVisibility(View.INVISIBLE);
horizonBar1.setVisibility(View.INVISIBLE);
horizonBar2.setVisibility(View.INVISIBLE);
defaultBar1.setVisibility(View.VISIBLE);
break;
case R.id.normal_horizon_bar1:
progress = 0;
progressText.setVisibility(View.VISIBLE);
defaultBar1.setVisibility(View.INVISIBLE);
horizonBar2.setVisibility(View.INVISIBLE);
horizonBar1.setVisibility(View.VISIBLE);
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
progress += 2;
if (progress <= 100) {
Message message = Message.obtain();
message.what = 0;
handler.sendMessage(message);
} else {
timer.cancel();
}
}
}, 0, 200);
break;
case R.id.normal_horizon_bar2:
progressText.setVisibility(View.VISIBLE);
defaultBar1.setVisibility(View.INVISIBLE);
horizonBar1.setVisibility(View.INVISIBLE);
horizonBar2.setVisibility(View.VISIBLE);
cacheProgress = 0;
progress = 0;
final Timer timer1 = new Timer();
timer1.schedule(new TimerTask() {
@Override
public void run() {
progress += 1;
cacheProgress += 2;
if (progress <= 100) {
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);
} else {
timer1.cancel();
}
}
}, 0, 400);
break;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="aoto.com.commonwidgetandlayout.basic_widget.progressBar.ProgressBarActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:gravity="center_horizontal">
<ProgressBar
android:id="@+id/normal_progress_bar_default"
android:layout_width="60dp"
android:layout_height="60dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:visibility="invisible" />
<ProgressBar
android:id="@+id/normal_progress_bar_horizon"
style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
android:progressDrawable="@drawable/progress_bar_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:max="100"
android:visibility="invisible" />
<ProgressBar
android:id="@+id/normal_progress_bar_horizon2"
android:progressDrawable="@drawable/progress_bar_second_back"
style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:max="100"
android:visibility="invisible" />
<TextView
android:id="@+id/progress_text"
android:layout_marginTop="20dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
<LinearLayout
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/normal_default_bar"
android:text="進度條1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:layout_marginLeft="20dp"
android:id="@+id/normal_horizon_bar1"
android:text="進度條2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:layout_marginLeft="20dp"
android:id="@+id/normal_horizon_bar2"
android:text="進度條3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
這個控件的可擴展性還是很高的,也是介紹控件到目前爲止唯一一個直接繼承View的控件,它的可擴展性還是很高的。這裏在github上看了一個ProgressBar不錯的開源項目,大家可以參考源碼學習一下:
好了,到這裏,關於ProgressBar的介紹接結束了。如果喜歡的話,歡迎掃描關注一波