最近在用原生的控件和布局绘制一些界面并使用,虽然这些都是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的介绍接结束了。如果喜欢的话,欢迎扫描关注一波