Android开发:从0到1 (清华开发者书库)
上QQ阅读APP看书,第一时间看更新

7.6 进度栏

进度栏(Progress Bar)可以反馈出后台任务是否正在处理或处理的进度,从而消除用户的心理等待时间。

在Android中,进度栏是android.widget.ProgressBar类,类图如图7-23所示,从图中可见android.widget.ProgressBar直接继承了android.view.View类。

图7-23 ProgressBar类图

7.6.1 进度栏相关属性和方法

进度栏有很多属性。下面是常用的几个属性:

❏ android:max。设置进度最大值。

❏ android:progress。设置当前进度。

❏ android:secondaryProgress。第二层进度栏进度。

❏ android:indeterminate。设置不确定模式进度栏,true为不确定模式。进度栏(ProgressBar)类中的常用方法如下:

❏ getMax()。返回进度最大值。

❏ getProgress()。返回进度值。

❏ getSecondaryProgress()。返回第二层进度栏进度值。

❏ incrementProgressBy(int diff)。设置增加进度。

❏ isIndeterminate()。判断是否为不确定模式。

❏ setIndeterminate(boolean indeterminate)。设置为不确定模式。

说明 什么是不确定模式(indeterminate)?一个任务的进度可以分为两种:可确定进度和不可确定进度。可确定进度是通过计算能够知道当前任务的进展情况,可以给用户一个完成的进度比例,还可以估算任务结束的时间。例如,估算Windows的安装进度,会显示安装了百分之几,还有多长时间完成。可确定进度模式能够给用户很好的体验;不可确定进度,是一些无法计算进展情况的任务,这些任务不知何时结束,但可以知道任务是进行还是停止。

Android系统提供了多种进度栏样式。其中一些与系统主题无关,如图7-24(a)、图7-24(d)、图7-24(f)所示;还有一些与系统主题有关,如图7-24(b)、图7-24(c)、图7-24(e)所示。下面是系统主题无关的6种样式:

图7-24 进度栏样式

❏ Widget.ProgressBar.Horizontal。水平条状进度栏。

❏ Widget.ProgressBar.Small。小圆形进度栏。

❏ Widget.ProgressBar.Large。大圆形进度栏。

❏ Widget.ProgressBar.Inverse。圆形进度栏。

❏ Widget.ProgressBar.Small.Inverse。小圆形进度栏。

❏ Widget.ProgressBar.Large.Inverse。大圆形进度栏。

在XML中,可以通过style="@android:style/ 进度栏样式 "进行设置,代码如下:

      <ProgressBar
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          style="@android:style/Widget.ProgressBar.Small"/>

另外,还有与系统主题有关的8种样式:

❏ progressBarStyleHorizontal。水平条状进度栏。

❏ progressBarStyleSmall。小圆形进度栏。

❏ progressBarStyle。圆形进度栏。

❏ progressBarStyleLarge。大圆形进度栏。

❏ progressBarStyleSmallInverse。小圆形进度栏。

❏ progressBarStyleInverse。圆形进度栏。

❏ progressBarStyleLargeInverse。大圆形进度栏。

❏ progressBarStyleSmallTitle。标题栏中进度栏。

在XML中,可以通过style="? android:attr/ 进度栏样式 "进行设置,代码如下:

      <ProgressBar
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          style="? android:attr/progressBarStyleSmall"/>

注意 前文style属性中带有Inverse和不带有Inverse的区别;当进度栏控件所在的背景颜色为白色时,需要使用带有Inverse的样式。它们的区别不是旋转方向相反。

7.6.2 实例1:水平条状进度栏

水平条状进度是样式设置为Horizontal进度栏,条状进度栏非常适合可确定进度(indeterminate = true)的情况,但也可展示不可确定进度(indeterminate = false)的情况。

下面通过实例了解它们的使用情况。实例如图7-25所示,单击-和+按钮可改变进度,条状进度还可以有双层进度栏样式。

布局文件activity_main.xml代码如下:

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"android:layout_height="match_parent"
          android:orientation="vertical">
          …
          <ProgressBar
              android:id="@+id/progress_horizontal01"
              android:layout_width="200dip"
              android:layout_height="wrap_content"
              style="@android:style/Widget.ProgressBar.Horizontal"                      ①
              android:max="100"                                                         ②
              android:progress="50"/>                                                   ③
          <!--包含按钮栏-->
          <include
              android:id="@+id/button_bar1"layout="@layout/button_bar"/>
          …
          <ProgressBar
              android:id="@+id/progress_horizontal02"
              style="? android:attr/progressBarStyleHorizontal"                         ④
              android:layout_width="200dip"
              android:layout_height="wrap_content"
              android:max="100"                                                         ⑤
              android:progress="50"                                                     ⑥
              android:secondaryProgress="75"/>                                          ⑦
          …
          <!--包含按钮栏-->
          <include
              android:id="@+id/button_bar2" layout="@layout/button_bar"/>
          …
          <!--包含按钮栏-->
          <include
              android:id="@+id/button_bar3" layout="@layout/button_bar"/>
          …
          <ProgressBar
              android:id="@+id/progress_horizontal03"
              style="? android:attr/progressBarStyleHorizontal"                         ⑧
              android:layout_width="200dip"
              android:layout_height="wrap_content"
              android:indeterminate="true"/>                                            ⑨
      </LinearLayout>

图7-25 条状进度栏实例

上述代码第①行是设置系统主题无关的水平条状进度栏。而代码第④行和第⑧行是设置系统主题相关的水平条状进度栏。

由于id为progress_horizontal01和progress_horizon-tal02的进度栏都是可确定进度的,因此需要知道设定最大值属性android:max,见代码第②行和第⑤行;当前进度an-droid:progress属性见代码第③行和第⑥行。另外,progress_horizontal02的进度栏有两层进度栏,需要设定android:sec-ondaryProgress属性,见代码第⑦行。

id为progress_horizontal03的进度栏是不可确定进度的,需要android:indeterminate属性设置为true,见代码第⑨行。而android:max、android:progress和android:second-aryProgress这些属性对于它没有意义,不需要设定。

说明 布局文件activity_main.xml中使用include标签的原因是界面中有三组-和+按钮,形式上完全一样,功能类似。因此将-和+两个按钮在另外一个布局button_bar.xml中声明。然后,在三个不同的地方通过include标签载入。这样,减少维护-和+两个按钮布局的工作量。

声明-和+两个按钮的布局文件button_bar.xml的代码如下:

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent" android:layout_height="wrap_content"
          android:orientation="horizontal">
          <Button
              android:id="@+id/decrease"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/progressbar_1_minus"/>
          <Button
              android:id="@+id/increase"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/progressbar_1_plus"/>
      </LinearLayout>

MainActivity.java代码如下:

        public class MainActivity extends AppCompatActivity{
            @Override
            protected void onCreate(Bundle savedInstanceState){
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                …
                final ProgressBar progressHorizontal02 =(ProgressBar) findViewById(R.id.progress_
        horizontal02);
                //获取被包含按钮栏button_bar2
                LinearLayout buttonBar2 =(LinearLayout) findViewById(R.id.button_bar2);     ①
                Button bar2IncreaseButton=(Button) buttonBar2.findViewById(R.id.increase);  ②
                bar2IncreaseButton.setOnClickListener(new Button.OnClickListener(){
                    public void onClick(View v){
                        progressHorizontal02.incrementProgressBy(1);                        ③
                    }
                });
                Button bar2DecreaseButton=(Button) buttonBar2.findViewById(R.id.decrease);  ④
                bar2DecreaseButton.setOnClickListener(new Button.OnClickListener(){
                    public void onClick(View v){
                        progressHorizontal02.incrementProgressBy(-1);                       ⑤
                    }
                });
                //获取被包含按钮栏button_bar3
                LinearLayout buttonBar3 =(LinearLayout) findViewById(R.id.button_bar3);
                Button bar3IncreaseButton=(Button) buttonBar3.findViewById(R.id.increase);  ⑥
                bar3IncreaseButton.setOnClickListener(new Button.OnClickListener(){
                    public void onClick(View v){
                        progressHorizontal02.incrementSecondaryProgressBy(1);               ⑦
                    }
                });
                Button bar3DecreaseButton=(Button) buttonBar3.findViewById(R.id.decrease);  ⑧
                bar3DecreaseButton.setOnClickListener(new Button.OnClickListener(){
                    public void onClick(View v){
                        progressHorizontal02.incrementSecondaryProgressBy(-1);              ⑨
                    }
                });
            }
        }

上述代码第③行和第⑤行是通过进度栏的incrementProgressBy方法增加和减少第一层进度栏的进度。代码第⑦行和第⑨行是通过进度栏的incrementSecondaryProgressBy方法增加和减少第二层进度栏的进度。

说明 在布局文件activity_main.xml中加载的button_bar.xml布局文件中声明了-和+两个按钮,它们的id是decrease和increase,如何获得这些按钮对象?解决办法是先通过MainActivity的findViewById方法,获得这些按钮所在的父视图(LinearLayout)对象,然后通过调父视图对象的findViewById方法获得按钮对象。例如,上述代码第①行findViewById(R.id.button_bar2)是获得父视图对象,参数id是在布局文件activity_main.xml的include android:id="@+id/button_bar2"layout="@layout/button_bar"/ 代码中声明的,代码第②行是调用父视图对象buttonBar2的findViewById获得+按钮。代码第④行是获得buttonBar2中-按钮,代码第⑥行是获得buttonBar3中的+按钮。

7.6.3 实例2:圆形进度栏

圆形进度栏一般应用在不可确定进度的任务,不需要设置android:max、android:progress和android:secondaryProgress等属性。

下面通过实例了解它们的使用情况。实例如图7-26所示,屏幕中有两个界面圆形进度栏和一个ToggleButton,通过单击ToggleButton可以隐藏或显示进度栏。

图7-26 圆形进度栏实例

布局文件activity_main.xml代码如下:

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"android:layout_height="match_parent"
          android:orientation="vertical">
          <ProgressBar
              android:id="@+id/progressBar1"
              style="? android:attr/progressBarStyleLarge"                               ①
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"/>
          <ProgressBar
              android:id="@+id/progressBar2" 
              style="@android:style/Widget.ProgressBar.Small"                            ②
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"/>
          <ToggleButton                                                                  ③
              android:id="@+id/toggleButton"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:textOff="隐藏"                                                      ④
              android:textOn="显示"/>                                                     ⑤
      </LinearLayout>

上述布局文件声明了两个进度栏,代码第①行是设置progressBar1进度栏样式中与系统主题有关的大圆形进度栏,代码第②行设置progressBar2进度栏样式中与系统主题无关的小圆形进度栏。

代码第③行声明了ToggleButton来实现进度栏隐藏和显示两种状态的切换。由于ToggleButton默认两种状态的标题是OFF或NO,手机设置为中文显示是“关闭”或“开启”,但是本例中需要显示“隐藏”或“显示”。

MainActivity.java代码如下:

        public class MainActivity extends AppCompatActivity{
            @Override
            protected void onCreate(Bundle savedInstanceState){
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);

                final ProgressBar progressBar1 =(ProgressBar) findViewById(R.id.progressBar1);
                final ProgressBar progressBar2 =(ProgressBar) findViewById(R.id.progressBar2);

                final ToggleButton button=(ToggleButton) findViewById(R.id.toggleButton);
                button.setOnClickListener(new Button.OnClickListener(){
                    public void onClick(View v){
                        boolean checked = button.isChecked();
                        if(checked){
                            progressBar1.setVisibility(ProgressBar.GONE);                   ①
                            progressBar2.setVisibility(ProgressBar.INVISIBLE);              ②
                        }else{
                            progressBar1.setVisibility(ProgressBar.VISIBLE);                ③
                            progressBar2.setVisibility(ProgressBar.VISIBLE);                ④
                        }
                    }
                });
            }
        }

上述代码第①、②、③、④行都是通过setVisibility方法设置进度栏的隐藏或显示,setVisibility方法中的参数有三个:

❏ ProgressBar.VISIBLE。显示,见代码第③和④行。

❏ ProgressBar.INVISIBLE。隐藏,占有空间。例如,上述代码progressBar2设置ProgressBar.INVISIBLE,结果如图7-26(b)所示,按钮顶部的空白是隐藏的progressBar2。

❏ ProgressBar.GONE。隐藏,不占有空间。例如,上述代码progressBar1设置ProgressBar.GONE,结果如图7-26(b)所示,按钮位置向上一段距离,事实上这个距离是progressBar1的高度。