Android ProgressBar具體解釋以及自己定義


  
版本號:1.0
日期:2014.5.16
版權:© 2014 kince 轉載注明出處

  這一次主要說一下Android下的進度條。為什么是它呢,由於最近被其各種美輪美奐的設計所傾倒,計划逐漸去實現。另外一個因素也是它也是為數不多的直接繼承於View類的控件,從中能夠學習到一些自己定義控件的知識。以下列舉了一些個人認為還算美麗的進度條。僅供參考。







  是不是非常美麗。事實上就像上面圖形展示的那樣。進度條大體上無非就是這幾種形式。

這樣一來肯定是須要自己定義了,所以方向有兩個:要么繼承於系統的ProgressBar。要么繼承於View類(前者就是如此實現)。那就先看一下系統的進度條吧。


   繼承於View類。直接子類有AbsSeekBar和ContentLoadingProgressBar。當中AbsSeekBar的子類有SeekBar和RatingBar,可見這二者也是基於ProgressBar實現的。

對於ProgressBar的使用,有三個地方須要注意一下:

  1、ProgressBar有兩個進度。一個是android:progress,另一個是android:secondaryProgress。后者主要是為緩存須要所涉及的。比方在看網絡視頻時候都會有一個緩存的進度條以及還要一個播放的進度,在這里緩存的進度就能夠是android:secondaryProgress,而播放進度就是android:progress。

  2、ProgressBar分為確定的和不確定的。上面說的播放進度、緩存等就是確定的。

相反地。不確定的就是不清楚、不確定一個操作須要多長時間來完畢,這個時候就須要用的不確定的ProgressBar了。這個是由屬性android:indeterminate來控制的,假設設置為true的話。那么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" 

  然后再看一下ProgressBar的其它經常使用屬性。

  關於這些屬性的使用還是比較簡單,不多做介紹。

當中第一個android:animationResolution已經唄舍棄了。所以不要去研究它了。重點說一下android:progressDrawable以及android:indeterminateDrawable。那這個Drawable在ProgressBar中是怎樣使用的呢,假設我們是這樣在xml中設置ProgressBar的話,

   <ProgressBar
        android:id="@+id/progressbar"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:secondaryProgress="50" />
   盡管沒有設置android:indeterminateDrawable,可是樣式Widget.ProgressBar.Horizontal已經幫我們設置好了。

查看源代碼例如以下:

    <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,源代碼例如以下:
<?

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>

  能夠看到。系統使用的是圖層方式,以覆蓋的方式進行的。所以假設須要其它的樣式的話,改變系統默認的值就可以。或者參考一下系統自帶的樣式設置就可以了。
  緊接着,說一下ProgressBar的方法,整體來說,能夠分為兩個部分。一是和自身屬性相關的。比方獲取進度、設置進度的最大值、設置插入器等等。

二是和繪制相關的部分,如圖所看到的:


  所以、所以我們本次最重要的部分來了。那就是怎樣自己定義一個美麗ProgressBar。

在自己定義之前。先看一下系統是怎樣實現的。

Android下ProgressBar的代碼量不算多,除去凝視預計也就是幾百行左右。首先從構造方法看是看,

  /**
     * 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();
    }
  樣式文件例如以下:
R.styleable.Progre:
 <declare-styleable name="ProgressBar">
        <!-- Defines the maximum value the progress can take. -->
        <attr name="max" format="integer" />
        <!-- Defines the default progress value, between 0 and max. -->
        <attr name="progress" format="integer" />
        <!-- 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. -->
        <attr name="secondaryProgress" format="integer" />
        <!-- Allows to enable the indeterminate mode. In this mode the progress
         bar plays an infinite looping animation. -->
        <attr name="indeterminate" format="boolean" />
        <!-- Restricts to ONLY indeterminate mode (state-keeping progress mode will not work). -->
        <attr name="indeterminateOnly" format="boolean" />
        <!-- Drawable used for the indeterminate mode. -->
        <attr name="indeterminateDrawable" format="reference" />
        <!-- Drawable used for the progress mode. -->
        <attr name="progressDrawable" format="reference" />
        <!-- Duration of the indeterminate animation. -->
        <attr name="indeterminateDuration" format="integer" min="1" />
        <!-- Defines how the indeterminate mode should behave when the progress
        reaches max. -->
        <attr name="indeterminateBehavior">
            <!-- 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" />
        </attr>
        <attr name="minWidth" format="dimension" />
        <attr name="maxWidth" />
        <attr name="minHeight" format="dimension" />
        <attr name="maxHeight" />
        <attr name="interpolator" format="reference" />
        <!-- Timeout between frames of animation in milliseconds
             {@deprecated Not used by the framework.} -->
        <attr name="animationResolution" format="integer" />
    </declare-styleable>
  ProgressBar把三個構造方法都列出來了。並使用了遞歸調用的方式,另一個方式就是分別在每個構造方法中都調用初始化的代碼,個人認為還是此處比較正規。然后看一下第三個構造方法,在這里主要做了兩件事情。一個是從attrs文件里讀取設置的屬性;一個是initProgressBar()方法,為ProgressBar設置一些默認的屬性值。
  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()方法,

 @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()方法,在
 @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類的方法,
  public boolean isLayoutRtl() {
        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
    }
  這個LAYOUT_DIRECTION_RTL是LayoutDirection的一個常量,
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。
一、繼承於系統ProgressBar
  首先看一下上面給出的進度條當中的一個。
  思路:
  Mini ProgressBar在原生ProgressBar的基礎上增加了一個指示器。並且有文字顯示。實現的時候能夠這樣。
  
  也就是說,自己定義的ProgressBar包括了兩個部分,一部分是默認的。另一部分是新增加的指示器。事實上指示器就是一個Drawable和文本的組合,並且直接畫在系統ProgressBar的上面就可以。接着。關於自己定義的ProgressBar的屬性也要定義一下,比方Drawable、比方文本、比方間隔等。所以attrs文件能夠這樣來寫了:

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

> <resources> <declare-styleable > <attr name= "progressIndicator" format="reference" ></attr> <attr name= "offset" format ="dimension"></ attr> <attr name= "textSize" format ="dimension"></ attr> <attr name= "textColor" format="reference|color" ></attr> <attr name= "textStyle"> <flag name= "normal" value ="0" /> <flag name= "bold" value ="1" /> <flag name= "italic" value ="2" /> </attr> <attr name= "textAlign"> <flag name= "left" value ="0" /> <flag name= "center" value ="1" /> <flag name= "right" value ="2" /> </attr> </declare-styleable > </resources>

  ps:我發現eclipse在寫declare-styleable不會自己主動提示,不清楚什么原因。知道的朋友望告知。

  
  之后我們新建一個類繼承於ProgressBar,
/**
 * @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,所以還須要聲明全局變量,初始化完畢后代碼例如以下:
 /**
*
*/
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方法,方便在程序中調用。

 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()方法中就能夠這樣來寫:

	@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()方法中增加了進度條的高度。所以在畫的時候須要將系統進度條與指示器分隔開來。在進度條的樣式文件里。我們是這樣配置的:
<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是這種:
<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" />
    </item >

</layer-list>
  能夠發現。是一個layer類型的drawable,所以在計算大小的時候。須要特別考慮這個情況。 代碼例如以下:
 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();
              }
          }
  然后須要更新進度條的位置。
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); } } } }

  最后,須要把指示器畫出來,
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();
          }
源代碼下載:
Github地址: https://github.com/wangjinyu501/SaundProgressBar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM