ProgressBar 是进度条组件,通常用于向用户展示某个耗时操作完成的进度,而不让用户感觉是程序失去了响应,从而更好地提升用户界面的友好性。
就像我现在进行的 apk 下载的任务,它都是通过进度条通知用户下载的进度,如果没有了这个进度条,不能实时地呈现下载进度的话,用户就会想是不是程序失去响应,而要下载的文件比较大的话,用户肯定会想知道下载到了什么地方,什么时候会完成,有了进度条都可以打消用户的这些疑虑。
用 Style 属性来给 ProgressBar 确定样式,有两种方式,第一种就是 API文档中说明的方式:
设置的方式如下:
style="@android:style/Widget.ProgressBar.Horizontal"
第二种就是使用系统的attr,下面的方式是系统的style:
style="?android:attr/progressBarStyleHorizontal"
style="@android:style/Widget.ProgressBar.Horizontal"
这两种都能实现水平ProgressBar样式,但效果并不一样。
我们可以通过你的SDK目录下…\platforms\android-25\data\res\values\styles.xml 查看系统的样式源码。如果是使用Android Studio的朋友就不需要这样了,可以Ctrl + 左键进入指定样式的源码。
系统自带的样式中最常用的就是以下三种了,分别代表小环形进度条,大环形进度条,水平进度条。这里并没有中型环形进度条,因为如果不设置 style 属性或者设置为 progressBarStyle 就显示为中等大小。
ProgressBar分为精确的和不精确的:
android:indeterminate 就是关于设置不精确的属性,因为 indeterminate 是不明确的意思,所以如果设置为true的话,滚动条的当前值会自动在最小到最大值之间来回移动,形成这样一个动画效果,这个只是告诉别人“我正在工作”,但不能提示工作进度到哪个阶段。主要是在进行一些无法确定操作时间的任务时作为提示。而设置为 false 就是根据我们的进度可以设置现在的进度值。
设置为true时,ProgressBar可能是圆形的滚动条或者水平的滚动条(由样式决定),但是我们一般时候,是直接使用Style类型来区分圆形还是水平ProgressBar的。
我们不仅可以在面板中显示不同风格的 ProgressBar,也可以在标题栏上设置,接下来就通过一个小案例来说明如何显示精确与不精确的两种 ProgressBar:
public class ProgressBar extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 启用窗口特征,启用带进度和不带进度的进度条
requestWindowFeature(Window.FEATURE_PROGRESS);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_progress_bar);
// 显示两种进度条
setProgressBarVisibility(true);
setProgressBarIndeterminateVisibility(true);
// Max=10000
setProgress(7000);
}
}
看到上面的代码就可以知道,FEATURE_PROGRESS就是注册启用精确的进度条在标题栏上,FEATURE_INDETERMINATE_PROGRESS则是相反,注册不精确的进度条。
然后用setProgressBarVisibility(),setProgressBarIndeterminateVisibility() 这两个方法设置它们的可见性,大家可以依照自己的需要在指定的地方调用这两种进度条的显示。如果不调用方法,即使注册了,也是默认不可见的。
而带进度的进度条的进度自然是有上限的,最大值就是10000,如果设置的是10000,那这两个进度条出现一下就会不见,所以在显示的基础上最大值是9999,我们在做下载或者播放视频的时候,通过进度的增加就可以达到与下载、播放的同步啦。
这里使用 Android Studio的朋友注意一下,因为Android Studio的工程Activity默认继承的AppCompactActivity,而这个是不支持我们这种用法的,所以我们要继承Activity,然后把styles.xml中的样式改成带标题栏的一种。
ProgressBar有两个进度,一个是android:progress(第一显示进度),另一个是android:secondaryProgress(第二显示进度)。后者主要是为缓存需要所设计的,比如在看网络视频时候都会有一个缓存的进度以及一个播放的进度,在这里缓存的进度就可以是android:secondaryProgress,而播放进度就是android:progress,所以我们在看视频的时候会经常看到除了当前的进度外还有一段浅色的进度。有了secondProgress,可以很方便定制ProgressBar。
除了这两个,还有一个关键的属性,那就是 android:max(最大显示进度)。我们可以通过第一显示进度除以最大显示进度得到一个百分比,用于计算当前下载或播放了多少。
至于android:indeterminate设置是否精确显示这个属性前面已经提到啦。
"match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="50"
android:secondaryProgress="80"
android:indeterminate="false" />
既然 ProgressBar 有第一进度、第二进度和最大进度,那么自然会方法来帮我们获取和处理这些进度,常用的方法如下:
public class ProgressBarActivity extends Activity implements View.OnClickListener {
private Button add;
private Button reduce;
private TextView text;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progress_bar);
add = (Button) findViewById(R.id.add);
reduce = (Button) findViewById(R.id.reduce);
text = (TextView) findViewById(R.id.text);
mProgressBar = (ProgressBar) findViewById(R.id.horizontal);
text.setText("第一进度:" + mProgressBar.getProgress() * 100.0 / mProgressBar.getMax() + "%" +
" 第二进度:" + mProgressBar.getSecondaryProgress() * 100.0 / mProgressBar.getMax() + "%");
add.setOnClickListener(this);
reduce.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.add:
mProgressBar.incrementProgressBy(10);
mProgressBar.setSecondaryProgress(mProgressBar.getProgress() + 30);
break;
case R.id.reduce:
mProgressBar.incrementProgressBy(-10);
mProgressBar.setSecondaryProgress(mProgressBar.getProgress() + 30);
break;
}
text.setText("第一进度:" + mProgressBar.getProgress() * 100.0 / mProgressBar.getMax() + "%" +
" 第二进度:" + mProgressBar.getSecondaryProgress() * 100.0 / mProgressBar.getMax() + "%");
}
除了我们刚说得在主布局文件中或者标题栏中去展示进度条以外,Android系统还给我们提供了一种以对话框形式展示进度条的方法,那就是使用ProgressDialog。
ProgressDialog的创建方式有两种,一种是new Dialog ,一种是调用Dialog的静态方法Dialog.show()。
//第一种方式:
ProgressDialog mProgressDialog = new ProgressDialog(this);
//第二种方式:
show(Context context, CharSequence title,
CharSequence message, boolean indeterminate,
boolean cancelable, OnCancelListener cancelListener)
//context 上下文
//title 对话框title
//message 对话框内容
//indeterminate 设置是否是不明确的状态
//cancelable 设置是否进度条是可以取消的
//cancelListener 用于监听进度条被取消
//上面参数除了前三个,都是可以省略的
//使用静态方式创建并显示,这种进度条只能是环形进度条
ProgressDialog mProgressDialog = ProgressDialog.show(this, "提示", "正在登陆中", true,
true, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
Toast.makeText(ProgressBarActivity.this, "进度条被取消",
Toast.LENGTH_SHORT).show();
}
});
ProgressDialog的样式有两种,一种是环形不明确状态,一种是水平进度条状态。
先来看环形进度条:
public class ProgressBarActivity extends Activity implements View.OnClickListener {
private Button show;
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progress_bar);
show = (Button) findViewById(dialog);
show.setOnClickListener(this);
mProgressDialog = new ProgressDialog(this);
}
@Override
public void onClick(View v) {
// 设置进度条的形式为圆形转动的进度条
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
// 设置是否可以通过点击Back键取消
mProgressDialog.setCancelable(false);
// 设置在点击Dialog外是否取消Dialog进度条
mProgressDialog.setCanceledOnTouchOutside(false);
// 设置提示的title的图标,默认是没有的,如果没有设置title的话只设置Icon是不会显示图标的
mProgressDialog.setIcon(R.mipmap.ic_launcher);
mProgressDialog.setTitle("提示");
// dismiss监听
mProgressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
// TODO Auto-generated method stub
Toast.makeText(ProgressBarActivity.this, "消失", Toast.LENGTH_SHORT).show();
}
});
// 监听Key事件被传递给dialog
mProgressDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode,
KeyEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case KeyEvent.ACTION_UP:
Toast.makeText(ProgressBarActivity.this, "up", Toast.LENGTH_SHORT).show();
break;
case KeyEvent.ACTION_DOWN:
Toast.makeText(ProgressBarActivity.this, "down", Toast.LENGTH_SHORT).show();
break;
}
return false;
}
});
// 监听cancel事件
mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// TODO Auto-generated method stub
Toast.makeText(ProgressBarActivity.this, "取消", Toast.LENGTH_SHORT).show();
}
});
//设置可点击的按钮,最多有三个(默认情况下)
mProgressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Toast.makeText(ProgressBarActivity.this, "确定", Toast.LENGTH_SHORT).show();
}
});
mProgressDialog.setMessage("这是一个圆形进度条");
mProgressDialog.show();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(5000);
// cancel和dismiss方法本质都是一样的,都是从屏幕中删除Dialog,唯一的区别是
// 调用cancel方法会回调DialogInterface.OnCancelListener,dismiss方法不会回调
mProgressDialog.cancel();
// mProgressDialog.dismiss();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
通过setProgressStyle()方法设置进度条的类型,那些属性的设置我都加了注释,大家应该都能看懂。这里我设置点击back键不会退出是为了后面更好地演示。
这里有三种监听事件,分别表示Dialog消失,Dialog取消,键盘监听。还有一个线程,表示如果长时间不退出Dialog就会自动退出。
演示中第一次退出Dialog是等线程结束自动退出,在过程中我点击Back键就触发了按下和抬起两个动作。第二次中点击确定后也确实触发了dismiss和cancel监听事件。
水平进度条:
@Override
public void onClick(View v) {
// 设置水平进度条
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setIcon(R.mipmap.ic_launcher);
mProgressDialog.setTitle("提示");
mProgressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Toast.makeText(ProgressBarActivity.this, "确定", Toast.LENGTH_SHORT).show();
}
});
mProgressDialog.setMessage("这是一个水平进度条");
mProgressDialog.show();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int i = 0;
while (i < 100 && mProgressDialog.getProgress() != 100) {
try {
Thread.sleep(200);
// 更新进度条的进度,可以在子线程中更新进度条进度
mProgressDialog.incrementProgressBy(1);
i++;
} catch (Exception e) {
// TODO: handle exception
}
}
// 在进度条走完时删除Dialog
mProgressDialog.dismiss();
}
}).start();
}
我在这里写得线程是当点击button时就会开始,因为是多线程,所以即使Dialog退出了线程也在进行着,而当进度条到头了,Dialog自动退出,再点击Button就不会有反应了。
以上就是所有ProgressBar的内容了,但要知道,无论是控件还是ProgressDialog,系统提供给我们的是无法满足所有要去的,我们更多的还是自定义控件来使用。
结束语:本文仅用来学习记录,参考查阅。