ProgressBar 组件也是一组重要的组件,ProgressBar 本身代表了进度条组件,它还派生了两个常用的组件:SeekBar 和 RatingBar。ProgressBar 及其子类在用法上十分相似,只是显示界面有一定的区别。因此本节把它们归为一类,针对它们的共性集中讲解,并突出介绍它们的区别。

ProgressBar 及其子类的继承关系图如图 2.50 所示。

安卓的ProgressBar进度条圆头 android进度条控件_android

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 属性。

安卓的ProgressBar进度条圆头 android进度条控件_进度条_02

表 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进度条圆头 android进度条控件_ProgressBar及其子类_03

实例:显示在标题上的进度条

还有一种进度条,可以直接在窗口标题上显示,这种进度条甚至不需要使用 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 所示界面。

安卓的ProgressBar进度条圆头 android进度条控件_ProgressBar及其子类_04

安卓的ProgressBar进度条圆头 android进度条控件_Android_05

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 所示界面。

安卓的ProgressBar进度条圆头 android进度条控件_ProgressBar及其子类_06

3,星级评分条(RatingBar)的功能和用法

星级评分条与拖动条有相同的父类:AbsSeekBar,因此它们十分相似。实际上星级评分条与拖动条的用法、功能都十分接近:它们都允许用户通过拖动来改变进度。RatingBar 与 SeekBar 最大区别在于:RatingBar 通过星星来表示进度。

表 2.28 显示了星级评分条所支持的常见 XML 属性。

安卓的ProgressBar进度条圆头 android进度条控件_进度条_07

为了让程序能响应星级评分条评分的改变,程序可以考虑为它绑定一个 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 所示界面。

安卓的ProgressBar进度条圆头 android进度条控件_安卓的ProgressBar进度条圆头_08