您的位置:首页 > 产品设计 > UI/UE

AndroidUI组件之ProgressBar

2015-10-21 11:16 495 查看
?
?
转载请注明出处:http://blog.csdn.net/android_jiangjun/article/details/2555563

ProgressBar简介



继承于View类,直接子类有AbsSeekBar和ContentLoadingProgressBar,其中AbsSeekBar的子类有SeekBar和RatingBar,可见这二者也是基于ProgressBar实现的。

1、ProgressBar有两个进度,一个是android:progress,另一个是android:secondaryProgress。后者主要是为缓存需要所涉及的,比如在看网络视频时候都会有一个缓存的进度条以及还要一个播放的进度,在这里缓存的进度就可以是android:secondaryProgress,而播放进度就是android:progress,有了secondProgress,可以很方便定制ProgressBar。

2、ProgressBar分为确定的和不确定的,确定的是我们能明确看到进度,相反不确定的就是不清楚、不确定一个操作需要多长时间来完成,这个时候就需要用的不确定的ProgressBar了。属性android:indeterminate如果设置为true的话,那么ProgressBar就可能是圆形的滚动条或者水平的滚动条(由样式决定),但是我们一般时候,是直接使用Style类型来区分圆形还是水平ProgressBar的。

3、ProgressBar的样式设定其实有两种方式,在API文档中说明的方式如下:

Widget.ProgressBar.Horizontal
Widget.ProgressBar.Small
Widget.ProgressBar.Large
Widget.ProgressBar.Inverse
Widget.ProgressBar.Small.Inverse
Widget.ProgressBar.Large.Inverse

使用的时候可以这样:style="@android:style/Widget.ProgressBar.Small",另外还有一种方式就是使用系统的attr,下面的方式是系统的style:

style="?android:attr/progressBarStyle"
style="?android:attr/progressBarStyleHorizontal"
style="?android:attr/progressBarStyleInverse"
style="?android:attr/progressBarStyleLarge"
style="?android:attr/progressBarStyleLargeInverse"
style="?android:attr/progressBarStyleSmall"
style="?android:attr/progressBarStyleSmallInverse"
style="?android:attr/progressBarStyleSmallTitle"

[java] view
plaincopy





<ProgressBar

android:id="@+id/progressBar1"

style="?android:attr/progressBarStyleHorizontal"

style="@android:style/Widget.ProgressBar.Horizontal"(等同于@android:attr)

android:layout_width="match_parent"

android:layout_height="wrap_content" />

水平ProgressBar系统样式

我们去看一下style="?android:attr/progressBarStyleHorizontal"的源码,如下:

[html] view
plaincopy





<pre name="code" class="java"> <style name="Widget.ProgressBar.Horizontal">

<item name="android:indeterminateOnly">false</item>

<item name="android:progressDrawable">@android:drawable/progress_horizontal</item>

<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>

<item name="android:minHeight">20dip</item>

<item name="android:maxHeight">20dip</item>

<item name="android:mirrorForRtl">true</item>

</style>


一眼看出android:progressDrawable便是主角,继续看一下progress_horizontal的源码,如下:

[java] view
plaincopy





<?xml version="1.0" encoding="utf-8"?>

<!-- Copyright (C) 2008 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

-->

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@android:id/background">

<shape>

<corners android:radius="5dip" />

<gradient

android:startColor="#ff9d9e9d"

android:centerColor="#ff5a5d5a"

android:centerY="0.75"

android:endColor="#ff747674"

android:angle="270"

/>

</shape>

</item>

<item android:id="@android:id/secondaryProgress">

<clip>

<shape>

<corners android:radius="5dip" />

<gradient

android:startColor="#80ffd300"

android:centerColor="#80ffb600"

android:centerY="0.75"

android:endColor="#a0ffcb00"

android:angle="270"

/>

</shape>

</clip>

</item>

<item android:id="@android:id/progress">

<clip>

<shape>

<corners android:radius="5dip" />

<gradient

android:startColor="#ffffd300"

android:centerColor="#ffffb600"

android:centerY="0.75"

android:endColor="#ffffcb00"

android:angle="270"

/>

</shape>

</clip>

</item>

</layer-list>

这里面有3个item,分别为:background、secondProgress、progress,看名字就能知道其大概作用,我们比较关心的应该是后两个,其实把这个文件copy一份到自己的项目下,就可以随心所欲的修改shape属性:圆角、渐变等等。

自定义水平ProgressBar

第一步,在drawable文件夹下新建一个progressbar_horizontal_1.xml:

[java] view
plaincopy





<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

<!-- background -->

<item

android:id="@android:id/background"

android:drawable="@drawable/progress_patch_green">

</item>

<!-- progress -->

<item android:id="@android:id/progress">

<clip>

<nine-patch android:src="@drawable/progress_patch_galy" />

</clip>

</item>

<!-- second progress -->

<item android:id="@android:id/secondaryProgress">

<clip>

<nine-patch android:src="@drawable/progresspatch_blue" />

</clip>

</item>

</layer-list>

上图中的progress和secondprogress中src的资源便是我自定义的,注意这三个之间的叠放顺序,background是最底层,中间的是progress最上层是second。

第二步,标准一点,在style中新建我们自定义的style:mProgress_horizontal:

[java] view
plaincopy





<style name="mProgress_horizontal">

<item name="android:indeterminateOnly">false</item>

<item name="android:progressDrawable">@drawable/progressbar_horizontal_1</item><!-- progress_horizontal -->

<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>

<item name="android:minHeight">20dip</item>

<item name="android:maxHeight">20dip</item>

</style>

上图中prpgressDrawable资源便是指向了我们自定义的progressbar_horizontal_1,大功告成。

第三步,组件引用:

[java] view
plaincopy





<ProgressBar

android:id="@+id/progressBar1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/progress_backround"

android:padding="5dp"

android:progress="50"

style="@style/mProgress_horizontal"

android:secondaryProgress="20"

android:visibility="visible" />

【附】

在这里我们也可以省略第二步创建style,直接在组件中android:progressDrawable引用自己的progressbar_horizontal_1,如下:

[java] view
plaincopy





<ProgressBar

android:id="@+id/progressBar1"

android:indeterminate="false"

android:indeterminateOnly="false"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/progress_backround"

android:padding="5dp"

android:progress="50"

android:maxHeight="20dp"

android:minHeight="20dp"

android:progressDrawable="@drawable/progressbar_horizontal_1"

android:secondaryProgress="20"

/>

第四步,效果图:



圆形ProgressBar系统样式

[java] view
plaincopy





<ProgressBar

android:id="@+id/progressBar2"

style="@android:attr/progressBarStyleLarge"

android:layout_gravity="center_vertical"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

我们以progressBarStyleLarge为例进行探索,找到这个布局文件,源码如下:

[java] view
plaincopy





<style name="Widget.ProgressBar.Large">

  <item name="android:indeterminateDrawable">@android:drawable/progress_large_white</item>

  <item name="android:minWidth">76dip</item>

  <item name="android:maxWidth">76dip</item>

  <item name="android:minHeight">76dip</item>

  <item name="android:maxHeight">76dip</item>

</style>

同样一眼看出indeterminateDrawable便是主角了,继续看一下progress_large_white源码,如下:

[java] view
plaincopy





<rotate xmlns:android="http://schemas.android.com/apk/res/android"

android:drawable="@drawable/spinner_white_76"

android:pivotX="50%"

android:pivotY="50%"

android:fromDegrees="0"

android:toDegrees="360" />

看到这里就透彻了,就是在这里spinner_white_76进行不停的旋转的,我们copy一下这个文件,就可以直接自定义了。

自定义圆形ProgressBar

第一步,在drawable文件夹下新建:progressbar_circle_1.xml,如下:

[java] view
plaincopy





<?xml version="1.0" encoding="utf-8"?>

<rotate xmlns:android="http://schemas.android.com/apk/res/android"

android:drawable="@drawable/loading" //自定义的菊花图片

android:fromDegrees="0"

android:pivotX="50%"

android:pivotY="50%"

android:toDegrees="360" >

</rotate>

第二步,在Style中定义mProgress_circle,如下:

[java] view
plaincopy





<style name="mProgress_circle">

<item name="android:indeterminateDrawable">@drawable/progressbar_circle_1</item>

<item name="android:minWidth">25dp</item>

<item name="android:minHeight">25dp</item>

<item name="android:maxWidth">60dp</item>

<item name="android:maxHeight">60dp</item>

</style>

支持大小自己随意定,别失真就好

第三步,组件中引用,如下:

[java] view
plaincopy





<ProgressBar

android:id="@+id/progressBar2"

style="@style/mProgress_circle"

android:layout_gravity="center_vertical"

android:layout_width="match_parent"

android:indeterminateDuration="1200"

android:layout_height="wrap_content" />

【附】

上面是通过一张图片填充android:indeterminateDrawable,我们也可以定义一个动画或者自定义颜色(shape)来实现,跟图片的用法一样:

定义动画 progress_circle_loading,xml:

[java] view
plaincopy





<?xml version="1.0" encoding="UTF-8"?>

<animation-list android:oneshot="false"

  xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:duration="100" android:drawable="@drawable/loading_1" />

  <item android:duration="100" android:drawable="@drawable/loading_2" />

  <item android:duration="100" android:drawable="@drawable/loading_3" />

  <item android:duration="100" android:drawable="@drawable/loading_4" />

  <item android:duration="100" android:drawable="@drawable/loading_5" />

  <item android:duration="100" android:drawable="@drawable/loading_6" />

</animation-list>

style的indeterminateDrawable引入:

[html] view
plaincopy





<pre name="code" class="java"><item name="android:indeterminateDrawable">@drawable/progress_circle_loading</item>



定义shape颜色 progress_circle_shape.xml

[java] view
plaincopy





<?xml version="1.0" encoding="utf-8"?>

<rotate xmlns:android="http://schemas.android.com/apk/res/android"

  android:fromDegrees="0"

  android:pivotX="50%"

  android:pivotY="50%"

  android:toDegrees="360" >

  <shape

    android:innerRadiusRatio="3"

    android:shape="ring"

    android:thicknessRatio="8"

    android:useLevel="false" >

    <gradient

      android:centerColor="#FFFFFF"

      android:centerY="0.50"

      android:endColor="#1E90FF"

      android:startColor="#000000"

      android:type="sweep"

      android:useLevel="false" />

  </shape>

</rotate>

style的indeterminateDrawable引入:

[java] view
plaincopy





<item name="android:indeterminateDrawable">@drawable/progress_circle_shape</item>

效果图如下:



SeekBar的原理是一样的,不信你看下图,我就是用的seekbar

最后来张全家福:



做过Android开发的同学应该都不会对这个控件陌生。主要是用来实现处理或加载进度的显示或者提示用户正在处理或加载数据。

基本来说就两种情况,一种是转圈的小菊花,一种是水平的进度条。

默认情况下ProgressBar是圆形的那种,如果你要设置成水平状的,需要加入style

Java代码


style="?android:attr/progressBarStyleHorizontal"

这两种形式的默认效果都不是很理想,个人认为Google的UI真的是丑到家了,不知道3.0之前是不是没有请UI呢?开个玩笑...

下面我们来看看ProgressBar中的style。通过style来简单分析下ProgressBar

首先在你的工程的res/values/styles.xml文件中加入下面的代码:

Java代码


<style

name="test" parent="@android:style/Widget.ProgressBar">

</style>

这只是为了方便你查看源码而已(我使用的是Eclipse,鼠标移到Widget.ProgressBar上,按下ctrl键即可),如果你的IDE看不到源码,也没有关系,你可以直接到源码的目录下找到这个style(比如我的sdk目录):

E:\androidSDK\sdk\platforms\android-7\data\res\values\styles.xml

然后找到“Widget.ProgressBar”即可:

Java代码


<style name="Widget.ProgressBar">

<item name="android:indeterminateOnly">true</item>

<item name="android:indeterminateDrawable">@android:drawable/progress_medium_white</item>

<item name="android:indeterminateBehavior">repeat</item>

<item name="android:indeterminateDuration">3500</item>

<item name="android:minWidth">48dip</item>

<item name="android:maxWidth">48dip</item>

<item name="android:minHeight">48dip</item>

<item name="android:maxHeight">48dip</item>

</style>

<style name="Widget.ProgressBar.Horizontal">

<item name="android:indeterminateOnly">false</item>

<item name="android:progressDrawable">@android:drawable/progress_horizontal</item>

<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>

<item name="android:minHeight">20dip</item>

<item name="android:maxHeight">20dip</item>

</style>

我把其中的Widget.ProgressBar和Widget.ProgressBar.Horizontal拿出来给大家看看。

indeterminate意思是“模糊的,不明确的”,而 android:indeterminateOnly这个属性如果设置为true,表示的是这个ProgressBar是模糊的,不明确的,也就是说,当前它并没有体现出具体的进度,只是一个小菊花在转(Widget.ProgressBar默认这个属性设置为true),对于水平ProgressBar的话,如果设置为true,则出现一个默认的加载的动画,即android:indeterminateDrawable中设置的

progress_indeterminate_horizonta.xml:

Java代码


<?xml version="1.0" encoding="utf-8"?>

<animation-list

xmlns:android="http://schemas.android.com/apk/res/android"

android:oneshot="false">

<item android:drawable="@drawable/progressbar_indeterminate1" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate2" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate3" android:duration="200" />

</animation-list>

这里面就是 3张这样的图片,在循环播放:



在布局文件中设置:

Java代码


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

tools:context=".MainActivity"

android:background="#ffffff" >

<!-- 圆形的progressBar -->

<ProgressBar

android:id="@+id/pb_circle"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="30dip"

android:layout_centerHorizontal="true"

/>

<!-- 水平的progressBar android:indeterminateOnly="true"-->

<ProgressBar

android:id="@+id/pb_horizontal"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerHorizontal="true"

android:layout_below="@+id/pb_circle"

android:layout_marginTop="30dip"

style="?android:attr/progressBarStyleHorizontal"

android:progress="50"

android:secondaryProgress="60"

android:minWidth="200dip"

android:indeterminateOnly="true"

/>

</RelativeLayout>

效果如下:



上面的水平ProgressBar中还设置了android:progress="50"和android:secondaryProgress="60"这两个属性,但是不起作用。这是因为我们设置了android:indeterminateOnly="true"

这个时候我们通常会想到在java代码中去将这个值设置为false,然后再设置进度progress,可是我并没有发现有这样的方法,查阅了sdk文档也没有发现,后来发现了有人利用了反射可已将源码中的mOnlyIndeterminate字段设置为false,这就达到了我们的目的了:

BeanUtils.java:

Java代码


public class BeanUtils {

private BeanUtils() {

}

/**

* 直接设置对象属性值,无视private/protected修饰符,不经过setter函数.

*/

public static void setFieldValue(final Object object, final String fieldName, final Object value) {

Field field = getDeclaredField(object, fieldName);

if (field == null)

throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");

makeAccessible(field);

try {

field.set(object, value);

} catch (IllegalAccessException e) {

Log.e("got exception:", "", e);

}

}

/**

* 循环向上转型,获取对象的DeclaredField.

*/

protected static Field getDeclaredField(final Object object, final String fieldName) {

return getDeclaredField(object.getClass(), fieldName);

}

/**

* 循环向上转型,获取类的DeclaredField.

*/

@SuppressWarnings("unchecked")

protected static Field getDeclaredField(final Class clazz, final String fieldName) {

for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {

try {

return superClass.getDeclaredField(fieldName);

} catch (NoSuchFieldException e) {

// Field不在当前类定义,继续向上转型

}

}

return null;

}

/**

* 强制转换fileld可访问.

*/

protected static void makeAccessible(Field field) {

if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {

field.setAccessible(true);

}

}

}

MainActivity.java:

Java代码


Timer timer = new Timer();

timer.schedule(new TimerTask()

{

@Override

public void run()

{

//执行的内容

BeanUtils.setFieldValue((Object)pbHorizontal, "mOnlyIndeterminate", (Object)Boolean.valueOf(false));

pbHorizontal.setIndeterminate(false);

pbHorizontal.setProgress(50);

pbHorizontal.setSecondaryProgress(60);

}

}, 3000);//表示3秒后执行

效果如下:



这样我们就可以实现:在正在加载数据之前显示默认的动画,而在加载数据的时候显示具体的进度。

还是存在这样一个大问题,那就是默认的ProgressBar的样式实在不敢恭维,当然通过上面的分析,我们可以很容易地对默认的style进行覆盖。

1.自定义小菊花进度条:

通过Widget.ProgressBar中的style的<item name="android:indeterminateDrawable">@android:drawable/progress_medium_white</item>我们去源码中查找:

progress_medium_white.xml:

Java代码


<?xml version="1.0" encoding="utf-8"?>

<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"

android:drawable="@drawable/spinner_white_48"

android:pivotX="50%"

android:pivotY="50%"

android:framesCount="12"

android:frameDuration="100" />

发现spinner_white_48是一张图片:



这就很简单了,我们可以替换掉style中默认的android:indeterminateDrawable为自己的drawable就可以了:

1.在res/drawable/indicate.xml:

Java代码


<?xml version="1.0" encoding="utf-8"?>

<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"

android:drawable="@drawable/indeterminate_progress_1"

android:pivotX="50%"

android:pivotY="50%"

/>

indeterminate_progress_1就是我们自定义的小菊花图片了

2.然后在布局文件中:

Java代码


<!-- 圆形的progressBar -->

<ProgressBar

android:id="@+id/pb_circle"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="30dip"

android:layout_centerHorizontal="true"

android:indeterminateDrawable="@drawable/indicate"

/>

就这么简单,看了很多人的博客,有的人采用的是10几张图片通过Progressbar进行播放,有的采用一个ImageView对10几张图片进行重复播放或者对一张图片进行旋转,我认为我的这种方式比较好,比较方便,而且只要一张图就够了。

2.自定义水平的ProgressBar:

我们要改变的是Widget.ProgressBar.Horizontal中的drawable/progress_horizontal和drawable/progress_indeterminate_horizontal

drawable/progress_horizontal.xml:

Java代码


<?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" />

<gradient

android:startColor="#ff9d9e9d"

android:centerColor="#ff5a5d5a"

android:centerY="0.75"

android:endColor="#ff747674"

android:angle="270"

/>

</shape>

</item>

<item android:id="@android:id/secondaryProgress">

<clip>

<shape>

<corners android:radius="5dip" />

<gradient

android:startColor="#80ffd300"

android:centerColor="#80ffb600"

android:centerY="0.75"

android:endColor="#a0ffcb00"

android:angle="270"

/>

</shape>

</clip>

</item>

<item android:id="@android:id/progress">

<clip>

<shape>

<corners android:radius="5dip" />

<gradient

android:startColor="#ffffd300"

android:centerColor="#ffffb600"

android:centerY="0.75"

android:endColor="#ffffcb00"

android:angle="270"

/>

</shape>

</clip>

</item>

</layer-list>

这实际上是通过xml来绘制图片,当然你可以以类似的方式来实现自己的效果。

progress_indeterminate_horizontal.xml:(这个在前面已经介绍过了)

Java代码


<?xml version="1.0" encoding="utf-8"?>

<animation-list

xmlns:android="http://schemas.android.com/apk/res/android"

android:oneshot="false">

<item android:drawable="@drawable/progressbar_indeterminate1" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate2" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate3" android:duration="200" />

</animation-list>

为了图方便,我直接到4.0的源码中,找到这个文件直接拿出来用,这样你就可以在4.0及以下的系统中看到4.0ProgressBar的效果了:

1.布局文件中:

Java代码


<ProgressBar

android:id="@+id/pb_horizontal"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_marginLeft="50dip"

android:layout_marginRight="50dip"

android:layout_centerHorizontal="true"

android:layout_below="@+id/pb_circle"

android:layout_marginTop="30dip"

style="?android:attr/progressBarStyleHorizontal"

android:progressDrawable="@drawable/pb_layer_list"

android:indeterminateDrawable="@drawable/bg_progressbar"

android:indeterminateOnly="true"

/>

2.res/drawable/pb_layout_list.xml:

Java代码


<?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/progress_bg_holo_dark" />

<item android:id="@android:id/secondaryProgress">

<scale android:scaleWidth="100%"

android:drawable="@drawable/progress_secondary_holo_dark" />

</item>

<item android:id="@android:id/progress">

<scale android:scaleWidth="100%"

android:drawable="@drawable/progress_primary_holo_dark" />

</item>

</layer-list>

3.res/drawable/bg_progressbar.xml:

Java代码


<?xml version="1.0" encoding="utf-8"?>

<animation-list

xmlns:android="http://schemas.android.com/apk/res/android"

android:oneshot="false">

<item android:drawable="@drawable/progressbar_indeterminate_holo1" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate_holo2" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate_holo3" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate_holo4" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate_holo5" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate_holo6" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate_holo7" android:duration="200" />

<item android:drawable="@drawable/progressbar_indeterminate_holo8" android:duration="200" />

</animation-list>

相应的图片文件你都可以在源码中找到。下面我们看看自定义后的运行效果:



信息量有点大,希望大家能够看的懂,如果自己能够去尝试一下,应该能够更好地了解。

主要的实现步骤在上面都以红颜色表示出来了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: