Android自己定义控件:进度条的四种实现方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自己定义控件:进度条的四种实现方式相关的知识,希望对你有一定的参考价值。

前三种实现方式代码出自:

http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/


(源代码下载)http://download.csdn.net/detail/chaoyu168/9616035


近期一直在学习自己定义控件,搜了很多大牛们Blog里分享的小教程。也上GitHub找了一些类似的控件进行学习。发现读起来都不太好懂,就想写这么一篇东西作为学习笔记吧。


一、控件介绍:

进度条在App中非经常见,比例如以下载进度、载入图片、打开文章、打开网页等等……都须要这么一个效果让用户知道我们的App正在读取。以构造良好的交互。假设没有这样一个效果的话。用户没法知道东西有没有下载好、图片载入了没有、文章打开了没……会让用户非常不爽。基于这种情景我们的UI设计师们创造了这样一个控件。


二、这篇文章会涉及的知识点:

跟我一样刚入门的Android菜鸟们。我推荐大家先了解一下这些知识点再往下看。

这些知识点我也会推荐一些博客给大家看看。更推荐大家看文档里的解释,当然大牛们能够直接无视……


1、ClipDrawable类:可以对一个drawable类进行剪切操作(即仅仅显示某一部分的区域,还有一部分隐藏),显示多大的区域由level控制(level取值是0~10000)

【博客:http://blog.csdn.net/lonelyroamer/article/details/8244777】、没文档的能够在这看【http://www.apihome.cn/api/android/ClipDrawable.html


2、自己定义View:guolin大神的深入学习View四部曲

Android LayoutInflater原理分析,带你一步步深入了解View——http://blog.csdn.net/guolin_blog/article/details/12921889】

Android视图绘制流程全然解析。带你一步步深入了解View——http://blog.csdn.net/guolin_blog/article/details/16330267】

Android视图状态及重绘流程分析,带你一步步深入了解View——http://blog.csdn.net/guolin_blog/article/details/17045157】

Android自己定义View的实现方法,带你一步步深入了解View——http://blog.csdn.net/guolin_blog/article/details/17357967】

3、没看过我写的:Android自己定义控件——老版优酷三级菜单的话,也许须要看看这个:

【RotateAnimation具体解释——http://blog.csdn.net/u012403246/article/details/41415799】

三、Android上的实现方式:

(前三种方法比較简单,第四种方法是GitHub项目的解析,对前三种没兴趣能够直接跳到后边……)


1、效果图:技术分享


将进度条的变换过程分解为一帧一帧的图片,将这些一帧一帧的图片连起来构成一个动画。

经常使用于:手机阅读网页、逛社区时,载入图片、文章等不须要清楚知道载入进度,可是须要知道是否进行载入的情景。


这样的方法实现能够通过创建一个animation-list的XML文件,然后给系统API提供的ProgressBar的indeterminateDrawable属性就能够了。(这个属性应该是类似于设置一个动画吧……)


XML:

[html] view plain copy
 技术分享技术分享
  1. <?

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

  2. <animation-list xmlns:android="http://schemas.android.com/apk/res/android"    
  3.     android:oneshot="false" >    
  4.     <item android:duration="150" >    
  5.         <clip     
  6.             android:clipOrientation="horizontal"    
  7.             android:drawable="@drawable/loading_01"    
  8.             android:gravity="left"/>    
  9.     </item>    
  10.     <item android:duration="150" >    
  11.         <clip     
  12.             android:clipOrientation="horizontal"    
  13.             android:drawable="@drawable/loading_02"    
  14.             android:gravity="left"/>    
  15.     </item>    
  16.     <item android:duration="150" >    
  17.         <clip     
  18.             android:clipOrientation="horizontal"    
  19.             android:drawable="@drawable/loading_03"    
  20.             android:gravity="left"/>    
  21.     </item>    
  22.     <item android:duration="150" >    
  23.         <clip     
  24.             android:clipOrientation="horizontal"    
  25.             android:drawable="@drawable/loading_04"    
  26.             android:gravity="left"/>    
  27.     </item>    
  28.     <item android:duration="150" >    
  29.         <clip     
  30.             android:clipOrientation="horizontal"    
  31.             android:drawable="@drawable/loading_05"    
  32.             android:gravity="left"/>    
  33.     </item>    
  34.     <item android:duration="150" >    
  35.         <clip     
  36.             android:clipOrientation="horizontal"    
  37.             android:drawable="@drawable/loading_06"    
  38.             android:gravity="left"/>    
  39.     </item>    
  40.     <item android:duration="150" >    
  41.         <clip     
  42.             android:clipOrientation="horizontal"    
  43.             android:drawable="@drawable/loading_07"    
  44.             android:gravity="left"/>    
  45.     </item>    
  46.     <item android:duration="150" >    
  47.         <clip     
  48.             android:clipOrientation="horizontal"    
  49.             android:drawable="@drawable/loading_08"    
  50.             android:gravity="left"/>    
  51.     </item>    
  52.     <item android:duration="150" >    
  53.         <clip     
  54.             android:clipOrientation="horizontal"    
  55.             android:drawable="@drawable/loading_09"    
  56.             android:gravity="left"/>    
  57.     </item>    
  58.     <item android:duration="150" >    
  59.         <clip     
  60.             android:clipOrientation="horizontal"    
  61.             android:drawable="@drawable/loading_10"    
  62.             android:gravity="left"/>    
  63.     </item>    
  64.     <item android:duration="150" >    
  65.         <clip     
  66.             android:clipOrientation="horizontal"    
  67.             android:drawable="@drawable/loading_11"    
  68.             android:gravity="left"/>    
  69.     </item>    
  70.     <item android:duration="150" >    
  71.         <clip     
  72.             android:clipOrientation="horizontal"    
  73.             android:drawable="@drawable/loading_12"    
  74.             android:gravity="left"/>    
  75.     </item>    
  76.     
  77. </animation-list>  


[html] view plain copy
 技术分享技术分享
  1. <ProgressBar     
  2.     android:layout_width="wrap_content"    
  3.     android:layout_height="wrap_content"    
  4.     android:indeterminateDrawable="@drawable/progressbar1"    
  5.     />  

2、效果图:技术分享

在上一篇有关自己定义控件的博客里我们使用了一个RotateAnimation类来实现旋转效果 (http://blog.csdn.net/u012403246/article/details/41309161),事实上。我们在这里也能够把一张图片,通过旋转。达到我们要的效果。本质上和上一种方法没多大差别。


我们仅仅须要创建一个rotate的XML。对其属性进行一些简单的设置。然后增加我们要用的图片就能够了。


XML:

[html] view plain copy
 技术分享技术分享
  1. <?xml version="1.0" encoding="utf-8"?>    
  2. <rotate xmlns:android="http://schemas.android.com/apk/res/android"    
  3.     android:pivotX="50%"    
  4.     android:pivotY="50%"    
  5.     android:fromDegrees="0"    
  6.     android:toDegrees="360"    
  7.     android:interpolator="@android:anim/accelerate_decelerate_interpolator" >    
  8.     <bitmap     
  9.         android:antialias="true"    
  10.         android:filter="true"    
  11.         android:src="@drawable/loading_360"/>    
  12.     
  13. </rotate>  

[html] view plain copy
 技术分享技术分享
  1. <ProgressBar     
  2.     android:layout_width="wrap_content"    
  3.     android:layout_height="wrap_content"    
  4.     android:indeterminateDrawable="@drawable/progressbar2"/>  

3、效果图:技术分享

我们能够弄两张照片。第一张是纯黑色的,然后把这张照片中心挖一个圆出来,圆区域弄成白色,挖出来的圆弄成第二张照片。我们最好还是叠加显示两张照片,刚開始把第二张全然“遮住”。随着载入进度的添加,我们降低遮住的区域把第二张照片慢慢的显示出来。


Android上刚好就有这么一个ClipDrawable类,可以实现剪裁的过程。

我们来看看怎么通过这种方式自己定义一个进度条控件。


代码:

[java] view plain copy
 技术分享技术分享
  1. public class MyProgressBar extends FrameLayout{    
  2.     private boolean running;    
  3.     private int progress = 0;    
  4.     private static final int MAX_PROGRESS = 10000;    
  5.         
  6.     private ClipDrawable clip;    
  7.         
  8.     private Handler handler = new Handler(){    
  9.         @Override    
  10.         public void handleMessage(android.os.Message msg) {    
  11.             if(msg.what == 0x123)    
  12.                 clip.setLevel(progress);    
  13.         }    
  14.     };    
  15.         
  16.     public MyProgressBar(Context context){    
  17.         this(context,null,0);    
  18.     }    
  19.     
  20.     public MyProgressBar(Context context,AttributeSet attrs){    
  21.         this(context,null,0);    
  22.     }    
  23.         
  24.     public MyProgressBar(Context context, AttributeSet attrs, int defStyle) {    
  25.         super(context, attrs, defStyle);    
  26.         Init(context);    
  27.     }    
  28.         
  29.     public void Init(Context context){    
  30.         View view = LayoutInflater.from(context).inflate(R.layout.view, null);    
  31.             
  32.         ImageView iv = (ImageView)view.findViewById(R.id.progress_img);    
  33.             
  34.         addView(view);    
  35.         clip = (ClipDrawable)iv.getDrawable();    
  36.             
  37.         Thread thread = new Thread(new Runnable() {    
  38.                 
  39.             @Override    
  40.             public void run() {    
  41.                 running = true;    
  42.                 while(running){    
  43.                     handler.sendEmptyMessage(0x123);    
  44.                     if(progress == MAX_PROGRESS)    
  45.                         progress = 0;    
  46.                     progress += 100;    
  47.                     try {    
  48.                         Thread.sleep(18);    
  49.                     } catch (InterruptedException e) {    
  50.                         e.printStackTrace();    
  51.                     }    
  52.                 }    
  53.             }    
  54.         });    
  55.         thread.start();    
  56.     }    
  57.     
  58.     public void stop(){    
  59.         progress = 0;    
  60.         running = false;    
  61.     }    
  62. }   

通过代码我们能够看到。逻辑很easy。关键就在于ClipDrawable的setLevel()方法,这个是设置剪裁效果的。


4、效果图:技术分享

实现一个View的子类——Progress Wheel类,实现进度条效果。

详细的内容我都写在了凝视上,假设不了解自己定义控件的知识。能够去阅读guolin博客里自己定义View四部曲的解说,讲的挺好的。


代码

[java] view plain copy
 技术分享技术分享
  1. public class ProgressWheel extends View {    
  2.     
  3.     //绘制View用到的各种长、宽带大小    
  4.     private int layout_height = 0;    
  5.     private int layout_width = 0;    
  6.     private int fullRadius = 100;    
  7.     private int circleRadius = 80;    
  8.     private int barLength = 60;    
  9.     private int barWidth = 20;    
  10.     private int rimWidth = 20;    
  11.     private int textSize = 20;    
  12.     private float contourSize = 0;    
  13.     
  14.     //与页边的间距    
  15.     private int paddingTop = 5;    
  16.     private int paddingBottom = 5;    
  17.     private int paddingLeft = 5;    
  18.     private int paddingRight = 5;    
  19.     
  20.     //View要绘制的颜色    
  21.     private int barColor = 0xAA000000;    
  22.     private int contourColor = 0xAA000000;    
  23.     private int circleColor = 0x00000000;    
  24.     private int rimColor = 0xAADDDDDD;    
  25.     private int textColor = 0xFF000000;    
  26.     
  27.     //绘制要用的画笔    
  28.     private Paint barPaint = new Paint();    
  29.     private Paint circlePaint = new Paint();    
  30.     private Paint rimPaint = new Paint();    
  31.     private Paint textPaint = new Paint();    
  32.     private Paint contourPaint = new Paint();    
  33.     
  34.     //绘制要用的矩形    
  35.     @SuppressWarnings("unused")    
  36.     private RectF rectBounds = new RectF();    
  37.     private RectF circleBounds = new RectF();    
  38.     private RectF circleOuterContour = new RectF();    
  39.     private RectF circleInnerContour = new RectF();    
  40.     
  41.     //动画    
  42.     //每次绘制要移动的像素数目    
  43.     private int spinSpeed = 2;    
  44.     //绘制过程的时间间隔    
  45.     private int delayMillis = 0;    
  46.     int progress = 0;    
  47.     boolean isSpinning = false;    
  48.     
  49.     //其它    
  50.     private String text = "";    
  51.     private String[] splitText = {};    
  52.     
  53.     /**  
  54.      * ProgressWheel的构造方法  
  55.      *  
  56.      * @param context  
  57.      * @param attrs  
  58.      */    
  59.     public ProgressWheel(Context context, AttributeSet attrs) {    
  60.         super(context, attrs);    
  61.     
  62.         parseAttributes(context.obtainStyledAttributes(attrs,    
  63.                 R.styleable.ProgressWheel));    
  64.     }    
  65.     
  66.     //----------------------------------    
  67.     //初始化一些元素    
  68.     //----------------------------------    
  69.     
  70.     /*  
  71.      * 调用这种方法时,使View绘制为方形  
  72.      * From: http://www.jayway.com/2012/12/12/creating-custom-android-views-part-4-measuring-and-how-to-force-a-view-to-be-square/  
  73.      *   
  74.      */    
  75.     @Override    
  76.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    
  77.         // 首先我们要调用超类的onMeasure借口     
  78.         // 原因是我们自己去实现一个方法获得长度、宽度太麻烦了    
  79.         // 使用超类的的方法很方便并且让复杂的细节可控    
  80.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);    
  81.     
  82.         // 在这里我们不能使用getWidth()和getHeight()。

         

  83.         // 由于这两个方法仅仅能在View的布局完毕后才干使用。而一个View的绘制过程是先绘制元素,再绘制Layout    
  84.         // 所以我们必须使用getMeasuredWidth()和getMeasuredHeight()    
  85.         int size = 0;    
  86.         int width = getMeasuredWidth();    
  87.         int height = getMeasuredHeight();    
  88.         int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();    
  89.         int heigthWithoutPadding = height - getPaddingTop() - getPaddingBottom();    
  90.             
  91.         // 最后我们用一些简单的逻辑去计算View的大小并调用setMeasuredDimension()去设置View的大小    
  92.         // 在比較View的长宽前我们不考虑间距,但当我们设置View所须要绘制的面积时。我们要考虑它    
  93.         // 不考虑间距的View(View内的实际画面)此时就应该是方形的,可是因为间距的存在,终于View所占的面积可能不是方形的     
  94.         if (widthWithoutPadding > heigthWithoutPadding) {    
  95.             size = heigthWithoutPadding;    
  96.         } else {    
  97.             size = widthWithoutPadding;    
  98.         }    
  99.             
  100.         // 假设你重写了onMeasure()方法。你必须调用setMeasuredDimension()方法     
  101.         // 这是你设置View大小的唯一途径      
  102.         // 假设你不调用setMeasuredDimension()方法,父控件会抛出异常。而且程序会崩溃    
  103.         // 假设我们使用了超类的onMeasure()方法,我们就不是那么须要setMeasuredDimension()方法    
  104.         // 然而,重写onMeasure()方法是为了改变既有的绘制流程。所以我们必须调用setMeasuredDimension()方法以达到我们的目的    
  105.         setMeasuredDimension(size + getPaddingLeft() + getPaddingRight(), size + getPaddingTop() + getPaddingBottom());    
  106.     }    
  107.     
  108.     /**  
  109.      * 使用onSizeChanged方法取代onAttachedToWindow获得View的面积  
  110.      * 由于这种方法会在測量了MATCH_PARENT和WRAP_CONTENT后立即被调用  
  111.      * 使用获得的面积设置View  
  112.      */    
  113.     @Override    
  114.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {    
  115.         super.onSizeChanged(w, h, oldw, oldh);    
  116.     
  117.         // Share the dimensions    
  118.         layout_width = w;    
  119.         layout_height = h;    
  120.     
  121.         setupBounds();    
  122.         setupPaints();    
  123.         invalidate();    
  124.     }    
  125.     
  126.     /**  
  127.      * 设置我们想要绘制的progress wheel的颜色  
  128.      */    
  129.     private void setupPaints() {    
  130.         barPaint.setColor(barColor);    
  131.         barPaint.setAntiAlias(true);    
  132.         barPaint.setStyle(Style.STROKE);    
  133.         barPaint.setStrokeWidth(barWidth);    
  134.     
  135.         rimPaint.setColor(rimColor);    
  136.         rimPaint.setAntiAlias(true);    
  137.         rimPaint.setStyle(Style.STROKE);    
  138.         rimPaint.setStrokeWidth(rimWidth);    
  139.     
  140.         circlePaint.setColor(circleColor);    
  141.         circlePaint.setAntiAlias(true);    
  142.         circlePaint.setStyle(Style.FILL);    
  143.     
  144.         textPaint.setColor(textColor);    
  145.         textPaint.setStyle(Style.FILL);    
  146.         textPaint.setAntiAlias(true);    
  147.         textPaint.setTextSize(textSize);    
  148.     
  149.         contourPaint.setColor(contourColor);    
  150.         contourPaint.setAntiAlias(true);    
  151.         contourPaint.setStyle(Style.STROKE);    
  152.         contourPaint.setStrokeWidth(contourSize);    
  153.     }    
  154.     
  155.     /**  
  156.      * 设置元素的边界  
  157.      */    
  158.     private void setupBounds() {    
  159.         // 为了保持宽度和长度的一致。我们要获得layout_width和layout_height中较小的一个,从而绘制一个圆    
  160.         int minValue = Math.min(layout_width, layout_height);    
  161.     
  162.         // 计算在绘制过程中在x,y方向的偏移量    
  163.         int xOffset = layout_width - minValue;    
  164.         int yOffset = layout_height - minValue;    
  165.     
  166.         // 间距加上偏移量    
  167.         paddingTop = this.getPaddingTop() + (yOffset / 2);    
  168.         paddingBottom = this.getPaddingBottom() + (yOffset / 2);    
  169.         paddingLeft = this.getPaddingLeft() + (xOffset / 2);    
  170.         paddingRight = this.getPaddingRight() + (xOffset / 2);    
  171.     
  172.         int width = getWidth(); //this.getLayoutParams().width;    
  173.         int height = getHeight(); //this.getLayoutParams().height;    
  174.     
  175.         rectBounds = new RectF(paddingLeft,    
  176.                 paddingTop,    
  177.                 width - paddingRight,    
  178.                 height - paddingBottom);    
  179.     
  180.         circleBounds = new RectF(paddingLeft + barWidth,    
  181.                 paddingTop + barWidth,    
  182.                 width - paddingRight - barWidth,    
  183.                 height - paddingBottom - barWidth);    
  184.         circleInnerContour = new RectF(circleBounds.left + (rimWidth / 2.0f) + (contourSize / 2.0f), circleBounds.top + (rimWidth / 2.0f) + (contourSize / 2.0f), circleBounds.right - (rimWidth / 2.0f) - (contourSize / 2.0f), circleBounds.bottom - (rimWidth / 2.0f) - (contourSize / 2.0f));    
  185.         circleOuterContour = new RectF(circleBounds.left - (rimWidth / 2.0f) - (contourSize / 2.0f), circleBounds.top - (rimWidth / 2.0f) - (contourSize / 2.0f), circleBounds.right + (rimWidth / 2.0f) + (contourSize / 2.0f), circleBounds.bottom + (rimWidth / 2.0f) + (contourSize / 2.0f));    
  186.     
  187.         fullRadius = (width - paddingRight - barWidth) / 2;    
  188.         circleRadius = (fullRadius - barWidth) + 1;    
  189.     }    
  190.     
  191.     /**  
  192.      * 从XML中解析控件的属性  
  193.      *  
  194.      * @param a the attributes to parse  
  195.      */    
  196.     private void parseAttributes(TypedArray a) {    
  197.         barWidth = (int) a.getDimension(R.styleable.ProgressWheel_barWidth,    
  198.                 barWidth);    
  199.     
  200.         rimWidth = (int) a.getDimension(R.styleable.ProgressWheel_rimWidth,    
  201.                 rimWidth);    
  202.     
  203.         spinSpeed = (int) a.getDimension(R.styleable.ProgressWheel_spinSpeed,    
  204.                 spinSpeed);    
  205.     
  206.         delayMillis = a.getInteger(R.styleable.ProgressWheel_delayMillis,    
  207.                 delayMillis);    
  208.         if (delayMillis < 0) {    
  209.             delayMillis = 0;    
  210.         }    
  211.     
  212.         barColor = a.getColor(R.styleable.ProgressWheel_barColor, barColor);    
  213.     
  214.         barLength = (int) a.getDimension(R.styleable.ProgressWheel_barLength,    
  215.                 barLength);    
  216.     
  217.         textSize = (int) a.getDimension(R.styleable.ProgressWheel_textSize,    
  218.                 textSize);    
  219.     
  220.         textColor = (int) a.getColor(R.styleable.ProgressWheel_textColor,    
  221.                 textColor);    
  222.     
  223.         //假设text是空的,就无视它    
  224.         if (a.hasValue(R.styleable.ProgressWheel_text)) {    
  225.             setText(a.getString(R.styleable.ProgressWheel_text));    
  226.         }    
  227.     
  228.         rimColor = (int) a.getColor(R.styleable.ProgressWheel_rimColor,    
  229.                 rimColor);    
  230.     
  231.         circleColor = (int) a.getColor(R.styleable.ProgressWheel_circleColor,    
  232.                 circleColor);    
  233.     
  234.         contourColor = a.getColor(R.styleable.ProgressWheel_contourColor, contourColor);    
  235.         contourSize = a.getDimension(R.styleable.ProgressWheel_contourSize, contourSize);    
  236.     
  237.     
  238.         // 使用TypedArray获得控件属性时必需要注意:使用结束后必须回收TypedArray的对象    
  239.         a.recycle();    
  240.     }    
  241.     
  242.     //----------------------------------    
  243.     //动画    
  244.     //----------------------------------    
  245.     
  246.     protected void onDraw(Canvas canvas) {    
  247.         super.onDraw(canvas);    
  248.         //绘制内圆    
  249.         canvas.drawArc(circleBounds, 360360false, circlePaint);    
  250.         //绘制边界    
  251.         canvas.drawArc(circleBounds, 360360false, rimPaint);    
  252.         canvas.drawArc(circleOuterContour, 360360false, contourPaint);    
  253.         canvas.drawArc(circleInnerContour, 360360false, contourPaint);    
  254.         //绘制条纹    
  255.         if (isSpinning) {    
  256.             canvas.drawArc(circleBounds, progress - 90, barLength, false,    
  257.                     barPaint);    
  258.         } else {    
  259.             canvas.drawArc(circleBounds, -90, progress, false, barPaint);    
  260.         }    
  261.         //绘制我们想要设置的文字 (并让它显示在圆水平和垂直方向的中心处)    
  262.         float textHeight = textPaint.descent() - textPaint.ascent();    
  263.         float verticalTextOffset = (textHeight / 2) - textPaint.descent();    
  264.     
  265.         for (String s : splitText) {    
  266.             float horizontalTextOffset = textPaint.measureText(s) / 2;    
  267.             canvas.drawText(s, this.getWidth() / 2 - horizontalTextOffset,    
  268.                     this.getHeight() / 2 + verticalTextOffset, textPaint);    
  269.         }    
  270.         if (isSpinning) {    
  271.             scheduleRedraw();    
  272.         }    
  273.     }    
  274.     
  275.     private void scheduleRedraw() {    
  276.         progress += spinSpeed;    
  277.         if (progress > 360) {    
  278.             progress = 0;    
  279.         }    
  280.         postInvalidateDelayed(delayMillis);    
  281.     }    
  282.     
  283.     /**  
  284.     *   推断wheel是否在旋转  
  285.     */    
  286.         
  287.     public boolean isSpinning() {    
  288.         if(isSpinning){    
  289.             return true;    
  290.         } else {    
  291.             return false;    
  292.         }    
  293.     }    
  294.         
  295.     /**  
  296.      * 重设进度条的值  
  297.      */    
  298.     public void resetCount() {    
  299.         progress = 0;    
  300.         setText("0%");    
  301.         invalidate();    
  302.     }    
  303.     
  304.     /**  
  305.      * 停止进度条的旋转  
  306.      */    
  307.     public void stopSpinning() {    
  308.         isSpinning = false;    
  309.         progress = 0;    
  310.         postInvalidate();    
  311.     }    
  312.     
  313.     
  314.     /**  
  315.      * 让进度条开启旋转模式  
  316.      */    
  317.     public void spin() {    
  318.         isSpinning = true;    
  319.         postInvalidate();    
  320.     }    
  321.     
  322.     /**  
  323.      * 让进度条每次添加1(最大值为360)  
  324.      */    
  325.     public void incrementProgress() {    
  326.         isSpinning = false;    
  327.         progress++;    
  328.         if (progress > 360)    
  329.             progress = 0;    
  330.         setText(Math.round(((float) progress / 360) * 100) + "%");    
  331.        postInvalidate();    
  332.     }    
  333.     
  334.     
  335.     /**  
  336.      * 设置进度条为一个确切的数值  
  337.      */    
  338.     public void setProgress(int i) {    
  339.         isSpinning = false;    
  340.         progress = i;    
  341.         postInvalidate();    
  342.     }    
  343.     
  344.     //----------------------------------    
  345.     //get和set方法    
  346.     //----------------------------------    
  347.     
  348.     /**  
  349.      * 设置progress bar的文字并不须要刷新View  
  350.      *  
  351.      * @param text the text to show (‘\n‘ constitutes a new line)  
  352.      */    
  353.     public void setText(String text) {    
  354.         this.text = text;    
  355.         splitText = this.text.split("\n");    
  356.     }    
  357.     
  358.     public int getCircleRadius() {    
  359.         return circleRadius;    
  360.     }    
  361.     
  362.     public void setCircleRadius(int circleRadius) {    
  363.         this.circleRadius = circleRadius;    
  364.     }    
  365.     
  366.     public int getBarLength() {    
  367.         return barLength;    
  368.     }    
  369.     
  370.     public void setBarLength(int barLength) {    
  371.         this.barLength = barLength;    
  372.     }    
  373.     
  374.     public int getBarWidth() {    
  375.         return barWidth;    
  376.     }    
  377.     
  378.     public void setBarWidth(int barWidth) {    
  379.         this.barWidth = barWidth;    
  380.             
  381.         if ( this.barPaint != null ) {    
  382.             this.barPaint.setStrokeWidth( this.barWidth );    
  383.         }    
  384.     }    
  385.     
  386.     public int getTextSize() {    
  387.         return textSize;    
  388.     }    
  389.     
  390.     public void setTextSize(int textSize) {    
  391.         this.textSize = textSize;    
  392.             
  393.         if ( this.textPaint != null ) {    
  394.             this.textPaint.setTextSize( this.textSize );    
  395.         }    
  396.     }    
  397.     
  398.     public int getPaddingTop() {    
  399.         return paddingTop;    
  400.     }    
  401.     
  402.     public void setPaddingTop(int paddingTop) {    
  403.         this.paddingTop = paddingTop;    
  404.     }    
  405.     
  406.     public int getPaddingBottom() {    
  407.         return paddingBottom;    
  408.     }    
  409.     
  410.     public void setPaddingBottom(int paddingBottom) {    
  411.         this.paddingBottom = paddingBottom;    
  412.     }    
  413.     
  414.     public int getPaddingLeft() {    
  415.         return paddingLeft;    
  416.     }    
  417.     
  418.     public void setPaddingLeft(int paddingLeft) {    
  419.         this.paddingLeft = paddingLeft;    
  420.     }    
  421.     
  422.     public int getPaddingRight() {    
  423.         return paddingRight;    
  424.     }    
  425.     
  426.     public void setPaddingRight(int paddingRight) {    
  427.         this.paddingRight = paddingRight;    
  428.     }    
  429.     
  430.     public int getBarColor() {    
  431.         return barColor;    
  432.     }    
  433.     
  434.     public void setBarColor(int barColor) {    
  435.         this.barColor = barColor;    
  436.             
  437.         if ( this.barPaint != null ) {    
  438.             this.barPaint.setColor( this.barColor );    
  439.         }    
  440.     }    
  441.     
  442.     public int getCircleColor() {    
  443.         return circleColor;    
  444.     }    
  445.     
  446.     public void setCircleColor(int circleColor) {    
  447.         this.circleColor = circleColor;    
  448.             
  449.         if ( this.circlePaint != null ) {    
  450.             this.circlePaint.setColor( this.circleColor);    
  451.         }    
  452.     }    
  453.     
  454.     public int getRimColor() {    
  455.         return rimColor;    
  456.     }    
  457.     
  458.     public void setRimColor(int rimColor) {    
  459.         this.rimColor = rimColor;    
  460.             
  461.         if ( this.rimPaint != null ) {    
  462.             this.rimPaint.setColor( this.rimColor );    
  463.         }    
  464.     }    
  465.     
  466.     
  467.     public Shader getRimShader() {    
  468.         return rimPaint.getShader();    
  469.     }    
  470.     
  471.     public void setRimShader(Shader shader) {    
  472.         this.rimPaint.setShader(shader);    
  473.     }    
  474.     
  475.     public int getTextColor() {    
  476.         return textColor;    
  477.     }    
  478.     
  479.     public void setTextColor(int textColor) {    
  480.         this.textColor = textColor;    
  481.             
  482.         if ( this.textPaint != null ) {    
  483.             this.textPaint.setColor( this.textColor );    
  484.         }    
  485.     }    
  486.     
  487.     public int getSpinSpeed() {    
  488.         return spinSpeed;    
  489.     }    
  490.     
  491.     public void setSpinSpeed(int spinSpeed) {    
  492.         this.spinSpeed = spinSpeed;    
  493.     }    
  494.     
  495.     public int getRimWidth() {    
  496.         return rimWidth;    
  497.     }    
  498.     
  499.     public void setRimWidth(int rimWidth) {    
  500.         this.rimWidth = rimWidth;    
  501.             
  502.         if ( this.rimPaint != null ) {    
  503.             this.rimPaint.setStrokeWidth( this.rimWidth );    
  504.         }    
  505.     }    
  506.     
  507.     public int getDelayMillis() {    
  508.         return delayMillis;    
  509.     }    
  510.     
  511.     public void setDelayMillis(int delayMillis) {    
  512.         this.delayMillis = delayMillis;    
  513.     }    
  514.         
  515.     public int getContourColor() {    
  516.         return contourColor;    
  517.     }    
  518.         
  519.     public void setContourColor(int contourColor) {    
  520.         this.contourColor = contourColor;    
  521.             
  522.         if ( contourPaint != null ) {    
  523.             this.contourPaint.setColor( this.contourColor );    
  524.         }    
  525.     }    
  526.         
  527.     public float getContourSize() {    
  528.         return this.contourSize;    
  529.     }    
  530.         
  531.     public void setContourSize(float contourSize) {    
  532.         this.contourSize = contourSize;    
  533.             
  534.         if ( contourPaint != null ) {    
  535.             this.contourPaint.setStrokeWidth( this.contourSize );    
  536.         }    
  537.     }    
  538. }    

























以上是关于Android自己定义控件:进度条的四种实现方式的主要内容,如果未能解决你的问题,请参考以下文章

Android 自己定义圆圈进度并显示百分比例控件(纯代码实现)

Android实现滑动的四种方式

Android基础控件ProgressBar进度条的使用

Android中的常用控件之进度条(ProgressBar)

Android中点击事件的四种写法详解

Android 高手进阶,自己定义圆形进度条