Android ProgressBar詳解以及自定義

版本:1.0日期:2014.5.16版權:© 2014 kince 轉載註明出處
這一次主要說一下Android下的進度條,爲何是它呢,由於近期被其各類美輪美奐的設計所傾倒,計劃逐漸去實現。另一個因素也是它也是爲數很少的直接繼承於View類的控件,從中 是否是很漂亮,其實就像上面圖形展現的那樣,進度條大致上無非就是這幾種形式。這樣一來確定是須要自定義了,因此方向有兩個:要麼繼承於系統的ProgressBar;要麼繼承於View類(前者就是如此實現)。那就先看一下系統的進度條吧。 \
繼承於View類,直接子類有AbsSeekBar和ContentLoadingProgressBar,其中AbsSeekBar的子類有SeekBar和RatingBar,可見這兩者也是基於ProgressBar實現的。對於ProgressBar的使用,有三個地方須要注意一下: 一、ProgressBar有兩個進度,一個是android:progress,另外一個是android:secondaryProgress。後者主要是爲緩存須要所涉及的,好比在看網絡視頻時候都會有一個緩存的進度條以及還要一個播放的進度,在這裏緩存的進度就能夠是android:secondaryProgress,而播放進度就是android:progress。 二、ProgressBar分爲肯定的和不肯定的,上面說的播放進度、緩存等就是肯定的。相反地,不肯定的就是不清楚、不肯定一個操做須要多長時間來完成,這個時候就須要用的不肯定的ProgressBar了。這個是由屬性android:indeterminate來控制的,若是設置爲true的話,那麼ProgressBar就多是圓形的滾動條或者水平的滾動條(由樣式決定)。默認狀況下,若是是水平進度條,那麼就是肯定的。 三、ProgressBar的樣式設定其實有兩種方式,在API文檔中說明的方式以下:
    Widget.ProgressBar.HorizontalWidget.ProgressBar.SmallWidget.ProgressBar.LargeWidget.ProgressBar.InverseWidget.ProgressBar.Small.InverseWidget.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" 而後再看一下ProgressBar的其餘經常使用屬性, \
      關於這些屬性的使用仍是比較簡單,很少作介紹。其中第一個android:animationResolution已經唄捨棄了,因此不要去研究它了。重點說一下android:progressDrawable以及android:indeterminateDrawable。那這個Drawable在ProgressBar中是如何使用的呢,若是咱們是這樣在xml中設置ProgressBar的話,

      ?html

      1android

      <progressbar android:id="@+id/progressbar" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:secondaryprogress="50"></progressbar>ios

      雖然沒有設置android:indeterminateDrawable,可是樣式Widget.ProgressBar.Horizontal已經幫咱們設置好了。查看源碼以下:express

      ?apache

      1canvas

      2緩存

      3網絡

      4app

      5less

      6

      7

      8

      <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>

      先看一下progress_horizontal,源碼以下:

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

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

      </gradient></corners></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">

      </gradient></corners></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">

      </gradient></corners></shape>

      </clip>

      </item>

      </layer-list>

      能夠看到,系統使用的是圖層方式,以覆蓋的方式進行的。因此若是須要其餘的樣式的話,改變系統默認的值便可,或者參考一下系統自帶的樣式設置就好了。
      緊接着,說一下ProgressBar的方法,整體來講,能夠分爲兩個部分。一是和自身屬性相關的,好比獲取進度、設置進度的最大值、設置插入器等等。二是和繪製相關的部分,如圖所示:\
      因此、因此咱們本次最重要的部分來了,那就是如何自定義一個漂亮ProgressBar。在自定義以前,先看一下系統是如何實現的。Android下ProgressBar的代碼量不算多,除去註釋估計也就是幾百行左右。首先從構造方法看是看,

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      /**

      * Create a new progress bar with range 0...100 and initial progress of 0.

      * @param context the application environment

      */

      public ProgressBar(Context context) {

      this(context, null);

      }

      public ProgressBar(Context context, AttributeSet attrs) {

      this(context, attrs, com.android.internal.R.attr.progressBarStyle);

      }

      public ProgressBar(Context context, AttributeSet attrs, int defStyle) {

      this(context, attrs, defStyle, 0);

      }

      /**

      * @hide

      */

      public ProgressBar(Context context, AttributeSet attrs, int defStyle, int styleRes) {

      super(context, attrs, defStyle);

      mUiThreadId = Thread.currentThread().getId();

      initProgressBar();

      TypedArray a =

      context.obtainStyledAttributes(attrs, R.styleable.ProgressBar, defStyle, styleRes);

      mNoInvalidate = true;

      Drawable drawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);

      if (drawable != null) {

      drawable = tileify(drawable, false);

      // Calling this method can set mMaxHeight, make sure the corresponding

      // XML attribute for mMaxHeight is read after calling this method

      setProgressDrawable(drawable);

      }

      mDuration = a.getInt(R.styleable.ProgressBar_indeterminateDuration, mDuration);

      mMinWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_minWidth, mMinWidth);

      mMaxWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_maxWidth, mMaxWidth);

      mMinHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_minHeight, mMinHeight);

      mMaxHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_maxHeight, mMaxHeight);

      mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);

      final int resID = a.getResourceId(

      com.android.internal.R.styleable.ProgressBar_interpolator,

      android.R.anim. linear_interpolator); // default to linear interpolator

      if (resID > 0) {

      setInterpolator(context, resID);

      }

      setMax(a.getInt(R.styleable.ProgressBar_max, mMax));

      setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));

      setSecondaryProgress(

      a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));

      drawable = a.getDrawable(R.styleable.ProgressBar_indeterminateDrawable);

      if (drawable != null) {

      drawable = tileifyIndeterminate(drawable);

      setIndeterminateDrawable(drawable);

      }

      mOnlyIndeterminate = a.getBoolean(

      R.styleable.ProgressBar_indeterminateOnly, mOnlyIndeterminate);

      mNoInvalidate = false;

      setIndeterminate( mOnlyIndeterminate || a.getBoolean(

      R.styleable.ProgressBar_indeterminate, mIndeterminate));

      mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);

      a.recycle();

      }

      樣式文件以下:

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      R.styleable.Progre:

      <declare-styleable name="ProgressBar">

      <!-- Defines the maximum value the progress can take. -->

      <!-- Defines the default progress value, between 0 and max. -->

      <!-- Defines the secondary progress value, between 0 and max. This progress is drawn between

      the primary progress and the background.  It can be ideal for media scenarios such as

      showing the buffering progress while the default progress shows the play progress. -->

      <!-- Allows to enable the indeterminate mode. In this mode the progress

      bar plays an infinite looping animation. -->

      <!-- Restricts to ONLY indeterminate mode (state-keeping progress mode will not work). -->

      <!-- Drawable used for the indeterminate mode. -->

      <!-- Drawable used for the progress mode. -->

      <!-- Duration of the indeterminate animation. -->

      <!-- Defines how the indeterminate mode should behave when the progress

      reaches max. -->

      <!-- Progress starts over from 0. -->

      <enum name="repeat" value="1">

      <!-- Progress keeps the current value and goes back to 0. -->

      <enum name="cycle" value="2">

      </enum></enum></attr>

      <!-- Timeout between frames of animation in milliseconds

      {@deprecated Not used by the framework.} -->

      </attr></attr></attr></attr></attr></attr></attr></attr></attr></attr></attr></attr></attr></attr></declare-styleable>

      ProgressBar把三個構造方法都列出來了,並使用了遞歸調用的方式,還有一個方式就是分別在每個構造方法中都調用初始化的代碼,我的以爲仍是此處比較正規。而後看一下第三個構造方法,在這裏主要作了兩件事情,一個是從attrs文件中讀取設置的屬性;一個是initProgressBar()方法,爲ProgressBar設置一些默認的屬性值。

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      private void initProgressBar() {

      mMax = 100;

      mProgress = 0;

      mSecondaryProgress = 0;

      mIndeterminate = false;

      mOnlyIndeterminate = false;

      mDuration = 4000;

      mBehavior = AlphaAnimation.RESTART;

      mMinWidth = 24;

      mMaxWidth = 48;

      mMinHeight = 24;

      mMaxHeight = 48;

      }

      這就是默認的屬性值。這在自定義View中算是最基礎的了,很少說,不過在這裏須要注意兩個地方。一是mUiThreadId,他是幹嗎的呢,它獲取的是當前UI線程的id,而後在更新ProgressBar進度的時候進行一個判斷,若是是UI線程,那麼直接進行更新,若是不是就post出去,使用Handler等進行更新。二是tileify(drawable, false)方法和tileifyIndeterminate(drawable)方法。這兩個方法主要是對Drawable進行一個解析、轉換的過程。在這裏須要重點強調一下,在ProgressBar中,最重要的部分就是Drawable的使用了,由於不只是它的背景包括進度等都是使用Drawable來完成的,因此在源碼中也能夠看到基本上百分之七八十的代碼都是和Drawable有關的。由於這一部分篇幅較多,因此就不詳細介紹了,下面重點說一下如何繪製ProgressBar,首先看onMeasure()方法,

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      @Override

      protected synchronized void onMeasure( int widthMeasureSpec, int heightMeasureSpec) {

      Drawable d = mCurrentDrawable;

      int dw = 0;

      int dh = 0;

      if (d != null) {

      dw = Math. max(mMinWidth , Math.min( mMaxWidth, d.getIntrinsicWidth()));

      dh = Math. max(mMinHeight , Math.min( mMaxHeight, d.getIntrinsicHeight()));

      }

      updateDrawableState();

      dw += mPaddingLeft + mPaddingRight;

      dh += mPaddingTop + mPaddingBottom;

      setMeasuredDimension( resolveSizeAndState(dw, widthMeasureSpec, 0),

      resolveSizeAndState(dh, heightMeasureSpec, 0));

      }

      這是測量View大小的方法,也就是ProgressBar的大小,由於每個ProgressBar默認都會使用Drawable。因此ProgressBar的大小便是Drawable的大小加上Padding的大小,若是沒有Padding,那很顯然就是Drawable的大小。最後使用setMeasuredDimension()方法設置ProgressBar的大小。 按照正常的流程,有些朋友可能會想到重寫onLayout()方法了,可是這裏ProgressBar只是一個View,不須要進行位置的處理。因此直接進入onDraw()方法,在

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      @Override

      protected synchronized void onDraw(Canvas canvas) {

      super.onDraw(canvas);

      Drawable d = mCurrentDrawable;

      if (d != null) {

      // Translate canvas so a indeterminate circular progress bar with padding

      // rotates properly in its animation

      canvas.save();

      if(isLayoutRtl() && mMirrorForRtl) {

      canvas.translate(getWidth() - mPaddingRight, mPaddingTop);

      canvas.scale(-1.0f, 1.0f);

      } else {

      canvas.translate(mPaddingLeft, mPaddingTop);

      }

      long time = getDrawingTime();

      if ( mHasAnimation) {

      mAnimation.getTransformation(time, mTransformation);

      float scale = mTransformation.getAlpha();

      try {

      mInDrawing = true;

      d.setLevel(( int) (scale * MAX_LEVEL));

      } finally {

      mInDrawing = false;

      }

      postInvalidateOnAnimation();

      }

      d.draw(canvas);

      canvas.restore();

      if ( mShouldStartAnimationDrawable && d instanceof Animatable) {

      ((Animatable) d).start();

      mShouldStartAnimationDrawable = false ;

      }

      }

      首先也是先獲取當前的Drawable對象,若是不爲空就開始繪圖,先是一個判斷,根據佈局的方向來轉移畫布,isLayoutRtl()是View類的方法,

      ?

      1

      2

      3

      public boolean isLayoutRtl() {

      return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);

      }

      這個LAYOUT_DIRECTION_RTL是LayoutDirection的一個常量,

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      package android.util;

      /**

      * A class for defining layout directions. A layout direction can be left-to-right (LTR)

      * or right-to-left (RTL). It can also be inherited (from a parent) or deduced from the default

      * language script of a locale.

      */

      public final class LayoutDirection {

      // No instantiation

      private LayoutDirection() {}

      /**

      * Horizontal layout direction is from Left to Right.

      */

      public static final int LTR = 0;

      /**

      * Horizontal layout direction is from Right to Left.

      */

      public static final int RTL = 1;

      /**

      * Horizontal layout direction is inherited.

      */

      public static final int INHERIT = 2;

      /**

      * Horizontal layout direction is deduced from the default language script for the locale.

      */

      public static final int LOCALE = 3;

      }

      而後再判斷有沒有動畫,若是有的話,就調用View類的postInvalidateOnAnimation()方法去執行一個動畫。最後調用Drawable對象去畫出來d.draw(canvas)。 總的來講,系統的ProgressBar是和Drawable緊密相關的,因此說,若是咱們自定義的ProgressBar和Drawable有關,那麼徹底能夠繼承於系統的ProgressBar來開發便可。若是你的自定義ProgressBar和Drawable關係不大,好比是這樣的,\ 其實,就不須要Drawable了,徹底能夠直接繼承於View類開發。 那下面就從兩個方面來自定義ProgressBar,1、繼承於系統ProgressBar 首先看一下上面給出的進度條其中的一個,\ 思路: Mini ProgressBar在原生ProgressBar的基礎上加入了一個指示器,而且有文字顯示。實現的時候能夠這樣,\也就是說,自定義的ProgressBar包含了兩個部分,一部分是默認的;另外一部分是新添加的指示器。其實指示器就是一個Drawable和文本的組合,並且直接畫在系統ProgressBar的上面便可。接着,關於自定義的ProgressBar的屬性也要定義一下,好比Drawable、好比文本、好比間隔等。因此attrs文件能夠這樣來寫了:

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

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

      <resources>

      <declare-styleable>

      </attr>

      <!-- attr-->

      <!-- attr-->

      </attr>

      <flag name="normal" value="0">

      <flag name="bold" value="1">

      <flag name="italic" value="2">

      </flag></flag></flag></attr>

      <flag name="left" value="0">

      <flag name="center" value="1">

      <flag name="right" value="2">

      </flag></flag></flag></attr>

      </attr></attr></declare-styleable>

      </resources>

      ps:我發現eclipse在寫declare-styleable不會自動提示,不清楚什麼緣由,知道的朋友望告知。 以後咱們新建一個類繼承於ProgressBar,

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      /**

      * @author kince

      *

      */

      public class IndicatorProgressBar extends ProgressBar {

      public IndicatorProgressBar(Context context) {

      this(context, null);

      }

      public IndicatorProgressBar(Context context, AttributeSet attrs) {

      this(context, attrs, 0);

      }

      public IndicatorProgressBar(Context context, AttributeSet attrs,

      int defStyle) {

      super(context, attrs, defStyle);

      }

      }

      而後在第三個構造方法中初始化數據,由於用到了文本以及Drawable,因此還須要聲明全局變量,初始化完畢後代碼以下:

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      /**

      *

      */

      package com.example.indicatorprogressbar.widget;

      import com.example.indicatorprogressbar.R;

      import android.content.Context;

      import android.content.res.TypedArray;

      import android.graphics.Color;

      import android.graphics.Paint;

      import android.graphics.Paint.Align;

      import android.graphics.drawable.Drawable;

      import android.text.TextPaint;

      import android.util.AttributeSet;

      import android.widget.ProgressBar;

      /**

      * @author kince

      *

      */

      public class IndicatorProgressBar extends ProgressBar {

      private TextPaint mTextPaint;

      private Drawable mDrawableIndicator;

      private int offset=5;

      public IndicatorProgressBar(Context context) {

      this(context, null);

      }

      public IndicatorProgressBar(Context context, AttributeSet attrs) {

      this(context, attrs, 0);

      mTextPaint=new TextPaint(Paint.ANTI_ALIAS_FLAG);

      mTextPaint.density=getResources().getDisplayMetrics().density;

      mTextPaint.setColor(Color.WHITE);

      mTextPaint.setTextSize(10);

      mTextPaint.setTextAlign(Align.CENTER);

      mTextPaint.setFakeBoldText(true);

      }

      public IndicatorProgressBar(Context context, AttributeSet attrs,

      int defStyle) {

      super(context, attrs, defStyle);

      TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.IndicatorProgressBar, defStyle, 0);

      if(array!=null){

      mDrawableIndicator=array.getDrawable(R.styleable.IndicatorProgressBar_progressIndicator);

      offset=array.getInt(R.styleable.IndicatorProgressBar_offset, 0);

      array.recycle();

      }

      }

      }

      而後,爲全局變量設置set、get方法,方便在程序中調用。

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      public Drawable getmDrawableIndicator() {

      return mDrawableIndicator ;

      }

      public void setmDrawableIndicator(Drawable mDrawableIndicator) {

      this.mDrawableIndicator = mDrawableIndicator;

      }

      public int getOffset() {

      return offset ;

      }

      public void setOffset(int offset) {

      this.offset = offset;

      }

      接下來,就是重寫onMeasure()、onDraw()方法了。在onMeasure()中,須要對進度條計算好具體大小,那根據上面的圖示,這個進度條的寬度和系統進度條的寬度是同樣的,也就是getMeasuredWidth();高度的話,由於加了一個指示器,因此高度是指示器的高度加上系統進度條的高度。所以在onMeasure()方法中就能夠這樣來寫:

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      @Override

      protected synchronized void onMeasure(int widthMeasureSpec,

      int heightMeasureSpec) {

      // TODO Auto-generated method stub

      super.onMeasure(widthMeasureSpec, heightMeasureSpec);

      if(mDrawableIndicator!=null){

      //獲取系統進度條的寬度 這個寬度也是自定義進度條的寬度 因此在這裏直接賦值

      final int width=getMeasuredWidth();

      final int height=getMeasuredHeight()+getIndicatorHeight();

      setMeasuredDimension(width, height);

      }

      }

      /**

      * @category 獲取指示器的高度

      * @return

      */

      private int getIndicatorHeight(){

      if(mDrawableIndicator==null){

      return 0;

      }

      Rect r=mDrawableIndicator.copyBounds();

      int height=r.height();

      return height;

      }

      而後是onDraw()方法,由於在onMeasure()方法中增長了進度條的高度,因此在畫的時候須要將系統進度條與指示器分隔開來。在進度條的樣式文件中,咱們是這樣配置的:

      ?

      1

      2

      3

      4

      5

      6

      7

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

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

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

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

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

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

      </style>

      在android:progressDrawable的屬性中,使用的drawable是這樣的:

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

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

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

      <item android:id="@+id/progress" android:drawable="@drawable/progressbar_bar">

      </item>

      <item android:id="@+id/pattern">

      <bitmap android:src="@drawable/progressbar_pattern" android:tilemode="repeat">

      </bitmap></item>

      </item></layer-list>

      能夠發現,是一個layer類型的drawable,因此在計算大小的時候,須要特別考慮這個狀況。代碼以下:

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      if (m_indicator != null) {

      if (progressDrawable != null

      && progressDrawable instanceof LayerDrawable) {

      LayerDrawable d = (LayerDrawable) progressDrawable;

      for (int i = 0; i < d.getNumberOfLayers(); i++) {

      d.getDrawable(i).getBounds(). top = getIndicatorHeight();

      d.getDrawable(i).getBounds(). bottom = d.getDrawable(i)

      .getBounds().height()

      + getIndicatorHeight();

      }

      } else if (progressDrawable != null) {

      progressDrawable.getBounds(). top = m_indicator

      .getIntrinsicHeight();

      progressDrawable.getBounds(). bottom = progressDrawable

      .getBounds().height() + getIndicatorHeight();

      }

      }

      而後須要更新進度條的位置,

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      private void updateProgressBar () {

      Drawable progressDrawable = getProgressDrawable();

      if (progressDrawable != null

      && progressDrawable instanceof LayerDrawable) {

      LayerDrawable d = (LayerDrawable) progressDrawable;

      final float scale = getScale(getProgress());

      // 獲取進度條 更新它的大小

      Drawable progressBar = d.findDrawableByLayerId(R.id.progress );

      final int width = d.getBounds(). right - d.getBounds().left ;

      if (progressBar != null) {

      Rect progressBarBounds = progressBar.getBounds();

      progressBarBounds. right = progressBarBounds.left

      + ( int ) (width * scale + 0.5f);

      progressBar.setBounds(progressBarBounds);

      }

      // 獲取疊加的圖層

      Drawable patternOverlay = d.findDrawableByLayerId(R.id.pattern );

      if (patternOverlay != null) {

      if (progressBar != null) {

      // 使疊加圖層適應進度條大小

      Rect patternOverlayBounds = progressBar.copyBounds();

      final int left = patternOverlayBounds.left ;

      final int right = patternOverlayBounds.right ;

      patternOverlayBounds. left = (left + 1 > right) ? left

      : left + 1;

      patternOverlayBounds. right = (right > 0) ? right - 1

      : right;

      patternOverlay.setBounds(patternOverlayBounds);

      } else {

      // 沒有疊加圖層

      Rect patternOverlayBounds = patternOverlay.getBounds();

      patternOverlayBounds. right = patternOverlayBounds.left

      + ( int ) (width * scale + 0.5f);

      patternOverlay.setBounds(patternOverlayBounds);

      }

      }

      }

      }

      最後,須要把指示器畫出來,

      ?

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      if (m_indicator != null) {

      canvas.save();

      int dx = 0;

      // 獲取系統進度條最右邊的位置 也就是頭部的位置

      if (progressDrawable != null

      && progressDrawable instanceof LayerDrawable) {

      LayerDrawable d = (LayerDrawable) progressDrawable;

      Drawable progressBar = d.findDrawableByLayerId(R.id.progress );

      dx = progressBar.getBounds(). right;

      } else if (progressDrawable != null) {

      dx = progressDrawable.getBounds().right ;

      }

      //加入offset

      dx = dx - getIndicatorWidth() / 2 - m_offset + getPaddingLeft();

      // 移動畫筆位置

      canvas.translate(dx, 0);

      // 畫出指示器

      m_indicator .draw(canvas);

      // 畫出進度數字

      canvas.drawText(

      m_formatter != null ? m_formatter .getText(getProgress())

      : Math.round(getScale(getProgress()) * 100.0f)

      + "%" , getIndicatorWidth() / 2,

      getIndicatorHeight() / 2 + 1, m_textPaint );

      // restore canvas to original

      canvas.restore();

      }

      源碼下載

相關文章
相關標籤/搜索