ProgressBar 组件也是一组重要的组件,ProgressBar 本身代表了进度条组件,它还派生了两个常用的组件:SeekBar 和 RatingBar。ProgressBar 及其子类在用法上十分相似,只是显示界面有一定的区别。因此本节把它们归为一类,针对它们的共性集中讲解,并突出介绍它们的区别。
ProgressBar 及其子类的继承关系图如图 2.50 所示。
1,进度条(ProgressBar)的功能与用法
进度条也是 UI 界面中的一种非常实用的组件,通常用于向用户显示某个耗时操作完成的百分比。进度条可以动态地显示进度,因此避免长时间地执行某个耗时操作时,让用户感觉程序失去了响应,从而更好地提供用户界面的友好性。
Android 支持几种风格的进度条,通过 style 属性可以为 ProgressBar 指定风格。该属性可支持如下几个属性值。
@android:style/Widget.ProgressBar.Horizontal:水平进度条。
@android:style/Widget.ProgressBar.Inverse:普通大小的环形进度条。
@android:style/Widget.ProgressBar.Large:大环形进度条。
@android:style/Widget.ProgressBar.Large.Inverse:大环形进度条。
@android:style/Widget.ProgressBar.Small:小环形进度条。
@android:style/Widget.ProgressBar.Inverse:小环形进度条。
除此之外,ProgressBar 还支持如表 2.27 所示的常用 XML 属性。
表 2.27 中 android:progressDrawable 用于指定进度条的轨道的绘制形式,该属性可指定为一个 LayerDrawable 对象(该对象可通过在 XML 文件中用<layer-list> 元素进行配置)的引用。
ProgressBar 提供了如下方法来操作进度。
setProgress(int):设置进度的完成百分比。
incrementProgressBy(int):设置进度条的进度增加或减少。当参数为正数时进度增加;当参数为负数时进度减少。
下面的程序简单示范了进度条的用法,该程序的界面布局文件只是定义了几个简单的进度条,并指定 style 属性为 @android:style/Widget.ProgressBar.Horizontal,即水平进度条。界面布局文件如下。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 定义一个大环形进度条 -->
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@android:style/Widget.ProgressBar.Large"
/>
<!-- 定义一个中等大小的环形进度条 -->
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<!-- 定义一个小环形进度条 -->
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@android:style/Widget.ProgressBar.Small"
/>
</LinearLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="任务完成的进度"/>
<!-- 定义一个水平进度条 -->
<ProgressBar
android:id="@+id/bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
style="@android:style/Widget.ProgressBar.Horizontal"
/>
<!-- 定义一个水平进度条,并改变轨道外观 -->
<ProgressBar
android:id="@+id/bar2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progressDrawable="@drawable/my_bar"
style="@android:style/Widget.ProgressBar.Horizontal"/>
</LinearLayout>
上面的布局文件中先定义了三个环形进度条,这种环形进度条显示进度,它只是显示一个不断旋转的图片。布局文件的后面定义的两个进度条的最大值为 100,第一个进度条的样式为水平进度;第二个进度条的外观被定义为 @drawable/my_bar,因此还需要在 drawable-mdpi 中定义如下文件。
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 定义轨道的背景 -->
<item android:id="@android:id/background"
android:drawable="@drawable/no" />
<!-- 定义轨道上已完成部分的样式 -->
<item android:id="@android:id/progress"
android:drawable="@drawable/ok" />
</layer-list>
下面的主程序用一个填充数组的任务模拟了耗时操作,并以进度条标识任务的完成百分比,主程序如下。
public class ProgressBarTest extends Activity
{
// 该程序模拟填充长度为100的数组
private int[] data = new int[100];
int hasData = 0;
// 记录ProgressBar的完成进度
int status = 0;
ProgressBar bar , bar2;
// 创建一个负责更新的进度的Handler
Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// 表明消息是由该程序发送的
if (msg.what == 0x111)
{
bar.setProgress(status);
bar2.setProgress(status);
}
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bar = (ProgressBar) findViewById(R.id.bar);
bar2 = (ProgressBar) findViewById(R.id.bar2);
// 启动线程来执行任务
new Thread()
{
public void run()
{
while (status < 100)
{
// 获取耗时操作的完成百分比
status = doWork();
// 发送消息
mHandler.sendEmptyMessage(0x111);
}
}
}.start();
}
// 模拟一个耗时的操作
public int doWork()
{
// 为数组元素赋值
data[hasData++] = (int) (Math.random() * 100);
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return hasData;
}
}
上面的程序中第 18,19 行代码用于修改进度条的完成进度。运行上面的程序将看到如图 2.51 所示界面。
实例:显示在标题上的进度条
还有一种进度条,可以直接在窗口标题上显示,这种进度条甚至不需要使用 ProgressBar 组件,它是直接由 Activity 的方法启用的。为了在窗口上显示进度条,需要经过如下两步。
(1)调用 Activity 的 requestWindowFeature() 方法,该方法根据传入的参数可启用特定对的窗口特征,例如传入 Window.FEATURE_INDETERMINATE_PROGRESS 在窗口标题上显示不带进度的进度条;传入 Window.FEATURE_PROGESS 则显示带进度的进度条。
(2)调用 Activity 的 setProgressBarVisibility(boolean) 或 setProgressBarIndeterminateVisibility(boolean) 方法即可控制进度条的显示和隐藏。
例如下面的程序,界面布局中仅仅定义了两个按钮,此处不再给出界面布局文件。该程序的 Activity 类代码如下。
public class TitleProgressBar extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// //设置窗口特征:启用显示进度的进度条
// requestWindowFeature(Window.FEATURE_PROGRESS); //①
//设置窗口特征:启用不显示进度的进度条
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); //②
setContentView(R.layout.main);
Button bn1 = (Button)findViewById(R.id.bn1);
Button bn2 = (Button)findViewById(R.id.bn2);
bn1.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
//显示不带进度的进度条。
setProgressBarIndeterminateVisibility(true);
//显示带进度的进度条。
setProgressBarVisibility(true);
//设置进度条的进度
setProgress(4500);
}
});
bn2.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
//隐藏不带进度的进度条。
setProgressBarIndeterminateVisibility(false);
//隐藏带进度的进度条。
setProgressBarVisibility(false);
}
});
}
}
上面的程序中①号代码控制窗口标题上显示带进度的进度条,而②号代码则控制窗口标题上显示不带进度的进度条。程序中两个按钮主要用于控制进度条的显示和隐藏。
如果程序启动窗口上显示带进度的进度条,则可看到如图 2.52 所示界面。
如果程序启动窗口上显示不带进度的进度条,则可看到如图 2.53 所示界面。
2,拖动条(SeekBar)的功能和用法
拖动条和进度条非常相似,只是进度条采用颜色填充来表明进度完成的程序,而拖动条则通过滑块的位置来标识数值 —— 而且拖动条允许用户拖动滑块来改变值,因此拖动条通常用于对系统的某种数值进行调节,比如调节音量等。
由于拖动条 SeekBar 继承了 ProgressBar,因此 ProgressBar 所支持的 XML 属性和方法完全适用于 SeekBar。
SeekBar 允许用户改变拖动条的滑块外观,改变滑块外观通过如下属性来指定。
android:thumb:指定一个 Drawable 对象,该对象将作为自定义滑块。
为了让程序能响应拖动条滑块位置的改变,程序可以考虑为它绑定一个 OnSeekBarChangeListener 监听器。
下面通过一个实例来示范 SeekBar 的功能和用法。
实例:通过拖动滑块来改变图片的透明度
该程序的界面布局中需要两个组件:一个 ImageView 用于显示图片,一个 SeekBar 用于动态改变图片的透明度。界面布局文件如下。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="240px"
android:src="@drawable/lijiang"
/>
<!-- 定义一个拖动条,并改变它的滑块外观 -->
<SeekBar
android:id="@+id/seekbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="255"
android:progress="255"
android:thumb="@drawable/ic_launcher"
/>
</LinearLayout>
上面的程序中第 18,19,20 行代码定义了该拖动条的最大值、当前值都是 255,并通过指定 android:thumb 属性来改变拖动条上滑块的外观。
该示例的主程序比较简单,程序只要为拖动条绑定一个监听器,当滑块位置发生改变时动态改变 ImageView 的透明度即可。主程序如下。
public class SeekBarTest extends Activity
{
ImageView image;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
image = (ImageView) findViewById(R.id.image);
SeekBar seekBar = (SeekBar) findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
{
// 当拖动条的滑块位置发生改变时触发该方法
@Override
public void onProgressChanged(SeekBar arg0, int progress,
boolean fromUser)
{
// 动态改变图片的透明度
image.setAlpha(progress);
}
@Override
public void onStartTrackingTouch(SeekBar bar)
{
}
@Override
public void onStopTrackingTouch(SeekBar bar)
{
}
});
}
}
上面的第 15至20 行代码就是监听拖动条上滑块位置发生改变的关键代码;当滑块位置发生改变时,ImageView 的透明度将变为该拖动条的当前数值。运行上面的程序将看到如图 2.54 所示界面。
3,星级评分条(RatingBar)的功能和用法
星级评分条与拖动条有相同的父类:AbsSeekBar,因此它们十分相似。实际上星级评分条与拖动条的用法、功能都十分接近:它们都允许用户通过拖动来改变进度。RatingBar 与 SeekBar 最大区别在于:RatingBar 通过星星来表示进度。
表 2.28 显示了星级评分条所支持的常见 XML 属性。
为了让程序能响应星级评分条评分的改变,程序可以考虑为它绑定一个 OnRatingBarChangeListener 监听器。
下面通过一个实例来示范 RatingBar 的功能和用法。
实例:通过星级改变图片的透明度
该程序其实只是前一个程序的简单改变,只是将上面程序中的 SeekBar 组件改为使用 RatingBar。下面是界面布局中关于 RatingBar 的代码片段。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="240px"
android:src="@drawable/lijiang"
/>
<!-- 定义一个星级评分条 -->
<RatingBar
android:id="@+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:max="255"
android:progress="255"
android:stepSize="0.5"
/>
</LinearLayout>
上面的界面布局中指定了该星级评分条的最大值为 255,当前进度为 255 —— 其中两个属性都来自于 ProgressBar 组件,这没有任何问题,因为 RatingBar 本来就是一个特殊的 ProgressBar。
主程序只要为 RatingBar 绑定事件监听器即可,监听星级评分条的星级改变。下面的主程序于星级评分条绑定监听器的代码。
public class RatingBarTest extends Activity
{
ImageView image;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
image = (ImageView) findViewById(R.id.image);
RatingBar ratingBar = (RatingBar) findViewById(R.id.rating);
ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener()
{
// 当拖动条的滑块位置发生改变时触发该方法
@Override
public void onRatingChanged(RatingBar arg0, float rating,
boolean fromUser)
{
// 动态改变图片的透明度,其中255是星级评分条的最大值
// 5个星星就代表最大值255
image.setAlpha((int) (rating * 255 / 5));
}
});
}
}
由于上面定义 RatingBar 时指定了 android:stepSize="0.5" ,因此该星级评分条中星级的最小变化为 0.5,也就是最少要变化半个星级。运行上面的程序将看到如图 2.55 所示界面。