aademeng

今天給大家带来的是自定义环形进度条的实现。虽然网上有各种方法实现环形进度条,但是我还是忍不住想写一下。

还是先看看效果吧!

当然我们也可以设置它的大小和圆环的宽度:

 

哈哈,是不是很有趣哩!接下来我们就看看是怎么实现的吧!

 

新建一个名为MyCircleProgressDemo的Android工程项目,目录如下:

首先得考虑该自定义View需要哪些属性,因此要在values目录下新建名为attrs.xml的文件用于自定义的属性:

 

[html] view plain copy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="myattrs">  
  4.         <attr name="circle_width" format="integer"/><!-- 自定义属性 circle_width 表示圆环的宽度-->  
  5.         <attr name="radius" format="integer"/><!-- 自定义属性 radius 表示圆环的半径-->  
  6.         <attr name="progress" format="integer"/><!-- 自定义属性 progress 表示圆环进度的初始值-->  
  7.         <attr name="max" format="integer"/><!-- 自定义属性 max 表示圆环进度的最大值-->  
  8.     </declare-styleable>  
  9. </resources>  

 

 

 

在attrs.xml文件中我们定义了四个属性。他们分别表示圆环的宽度,圆环的半径,圆环进度的初始值和圆环进度的最大值。

 

接下来就是自定义圆环的实现MyCircleProgress.Java

 

[java] view plain copy
 
  1. package com.example.myview;  
  2.   
  3. import com.example.mycircleprogressdemo.R;  
  4.   
  5. import android.content.Context;  
  6. import android.content.res.TypedArray;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Color;  
  9. import android.graphics.Paint;  
  10. import android.graphics.RectF;  
  11. import android.util.AttributeSet;  
  12. import android.view.View;  
  13.   
  14. /** 
  15.  * @author Joker_Ya 
  16.  */  
  17. public class MyCircleProgress extends View {  
  18.   
  19.     private int progress;  
  20.     // 设置最大值  
  21.     private int max;  
  22.     // 圓環寬度  
  23.     private int circleWidth;  
  24.     // 控件的寬度  
  25.     private int width;  
  26.     // 控件的高度  
  27.     private int height;  
  28.     // 默認圓的半徑  
  29.     private int radius;  
  30.     // 绘制轨迹的画笔  
  31.     private Paint paint;  
  32.     // 绘制填充的画笔  
  33.     private Paint fillpaint;  
  34.   
  35.     private RectF oval;  
  36.     // View重绘标志  
  37.     private boolean reset = false;  
  38.     // 设置监听  
  39.     private ProgressChangeListener listener = null;  
  40.   
  41.     public MyCircleProgress(Context context, AttributeSet attrs) {  
  42.         super(context, attrs);  
  43.         // TODO Auto-generated constructor stub  
  44.         // 获得自定义属性  
  45.         TypedArray mArray = context.obtainStyledAttributes(attrs,  
  46.                 R.styleable.myattrs);  
  47.         // 获得自定义属性的初始进度属性,否则返回0  
  48.         progress = mArray.getInteger(R.styleable.myattrs_progress, 0);  
  49.         // 获得自定义属性的最大进度值属性,否则返回100  
  50.         max = mArray.getInteger(R.styleable.myattrs_max, 100);  
  51.         // 获得自定义属性的圆环宽度属性,否则返回20  
  52.         circleWidth = mArray.getInteger(R.styleable.myattrs_circle_width, 20);  
  53.         // 获得自定义属性的半径属性,否则返回120  
  54.         radius = mArray.getInteger(R.styleable.myattrs_radius, 120);  
  55.   
  56.         paint = new Paint();  
  57.         // 抗锯齿  
  58.         paint.setAntiAlias(true);  
  59.         // 帮助抗锯齿  
  60.         paint.setFlags(Paint.ANTI_ALIAS_FLAG);  
  61.         // 设置样式为空心  
  62.         paint.setStyle(Paint.Style.STROKE);  
  63.         paint.setDither(true);  
  64.         paint.setStrokeJoin(Paint.Join.ROUND);  
  65.   
  66.         fillpaint = new Paint();  
  67.         // 抗锯齿  
  68.         fillpaint.setAntiAlias(true);  
  69.         // 帮助抗锯齿  
  70.         fillpaint.setFlags(Paint.ANTI_ALIAS_FLAG);  
  71.         // 设置样式为空心  
  72.         fillpaint.setStyle(Paint.Style.STROKE);  
  73.         fillpaint.setDither(true);  
  74.         fillpaint.setStrokeJoin(Paint.Join.ROUND);  
  75.   
  76.         oval = new RectF();  
  77.         // 回收mArray  
  78.         mArray.recycle();  
  79.     }  
  80.   
  81.     @Override  
  82.     protected void onDraw(Canvas canvas) {  
  83.         // TODO Auto-generated method stub  
  84.         super.onDraw(canvas);  
  85.         if (reset) {  
  86.             canvas.drawColor(Color.TRANSPARENT);  
  87.             reset = false;  
  88.         }  
  89.         // 获得组件的宽高  
  90.         width = getMeasuredWidth();  
  91.         height = getMeasuredHeight();  
  92.         // 获得半径  
  93.         radius = width / 2 - circleWidth;  
  94.         // 设置画笔颜色  
  95.         paint.setColor(Color.GREEN);  
  96.         // 设置画笔宽度  
  97.         paint.setStrokeWidth(circleWidth);  
  98.         // 中心画圆  
  99.         canvas.drawCircle(width / 2, height / 2, radius, paint);  
  100.   
  101.         /* 绘制边线 */  
  102.         // 画笔宽度  
  103.         paint.setStrokeWidth(1f);  
  104.         // 边线颜色  
  105.         paint.setColor(Color.BLACK);  
  106.         canvas.drawCircle(width / 2, height / 2, radius + circleWidth / 2  
  107.                 + 0.5f, paint);  
  108.         canvas.drawCircle(width / 2, height / 2, radius - circleWidth / 2  
  109.                 - 0.5f, paint);  
  110.         // 设置填充画笔的类型,边角是圆角的  
  111.         fillpaint.setStrokeCap(Paint.Cap.ROUND);  
  112.         // 画笔宽度  
  113.         fillpaint.setStrokeWidth(circleWidth);  
  114.         // 设置左上角和右下角坐标  
  115.         oval.set(width / 2 - radius, height / 2 - radius, width / 2 + radius,  
  116.                 height / 2 + radius);  
  117.         // 绘制圆弧。第二个参数为起始角度,第三个为跨越的角度,第三個为实心,true为实心,false为空心  
  118.         canvas.drawArc(oval, -90, ((float) progress / max) * 360, false,  
  119.                 fillpaint);  
  120.     }  
  121.   
  122.     @Override  
  123.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  124.         // TODO Auto-generated method stub  
  125.         int width = View.MeasureSpec.getSize(widthMeasureSpec);  
  126.         int height = View.MeasureSpec.getSize(heightMeasureSpec);  
  127.         setMeasuredDimension(width, height);  
  128.     }  
  129.   
  130.     // 定义接口ProgressChangeListener  
  131.     public interface ProgressChangeListener {  
  132.         public void ProgressChange(int progress1);  
  133.   
  134.         public void onComplete(int progress2);  
  135.     }  
  136.   
  137.     public void setProgressChangeListener(ProgressChangeListener listener) {  
  138.         // TODO Auto-generated method stub  
  139.         this.listener = listener;  
  140.     }  
  141.   
  142.     // 设置进度  
  143.     public void setProgress(int progress) {  
  144.         this.progress = progress;  
  145.         this.invalidate();  
  146.         if (listener != null) {  
  147.             if (this.max <= this.progress) {  
  148.                 listener.onComplete(progress);  
  149.             } else {  
  150.                 listener.ProgressChange(progress);  
  151.             }  
  152.         }  
  153.     }  
  154.   
  155.     // 重置进度  
  156.     public void reset() {  
  157.         reset = true;  
  158.         progress = 0;  
  159.         // 重绘  
  160.         invalidate();  
  161.     }  
  162.   
  163. }  


代码里的注释很详细了,在这就简单的说一下:得到控件的宽高-->得到中心点-->以中心点为坐标画圆环-->给圆环内外加上表框-->根据progress绘制圆弧。大概就是这样吧!

 

 

 

然后是MainActivity.java:

 

[java] view plain copy
 
  1. package com.example.mycircleprogressdemo;  
  2.   
  3. import com.example.myview.MyCircleProgress;  
  4. import com.example.myview.MyCircleProgress.ProgressChangeListener;  
  5.   
  6. import android.support.v7.app.ActionBarActivity;  
  7. import android.os.Bundle;  
  8. import android.os.Handler;  
  9. import android.os.Message;  
  10. import android.view.Menu;  
  11. import android.view.MenuItem;  
  12.   
  13. /** 
  14.  * @author Joker_Ya 
  15.  */  
  16. public class MainActivity extends ActionBarActivity {  
  17.   
  18.     private MyCircleProgress myCircleProgress;  
  19.     private int progress = 0;  
  20.     private Handler handler = new Handler() {  
  21.   
  22.         @Override  
  23.         public void handleMessage(Message msg) {  
  24.             // TODO Auto-generated method stub  
  25.             switch (msg.what) {  
  26.             case 0x123:  
  27.                 addProgress();  
  28.                 break;  
  29.   
  30.             default:  
  31.                 break;  
  32.             }  
  33.         }  
  34.     };  
  35.   
  36.     @Override  
  37.     protected void onCreate(Bundle savedInstanceState) {  
  38.         super.onCreate(savedInstanceState);  
  39.         setContentView(R.layout.activity_main);  
  40.   
  41.         myCircleProgress = (MyCircleProgress) findViewById(R.id.my_circleprogress);  
  42.         // 设置监听  
  43.         myCircleProgress  
  44.                 .setProgressChangeListener(new ProgressChangeListener() {  
  45.   
  46.                     @Override  
  47.                     public void ProgressChange(int progress1) {  
  48.                         // TODO Auto-generated method stub  
  49.                     }  
  50.   
  51.                     @Override  
  52.                     public void onComplete(int progress2) {  
  53.                         // TODO Auto-generated method stub  
  54.                         progress = 0;  
  55.                         // 重置进度  
  56.                         myCircleProgress.reset();  
  57.                     }  
  58.                 });  
  59.         addProgress();  
  60.     }  
  61.   
  62.     // 该方法让progress每次加上10  
  63.     public void addProgress() {  
  64.         progress += 10;  
  65.         myCircleProgress.setProgress(progress);  
  66.         handler.sendEmptyMessageDelayed(0x123, 1000);  
  67.     }  
  68.   
  69.     @Override  
  70.     public boolean onCreateOptionsMenu(Menu menu) {  
  71.         // Inflate the menu; this adds items to the action bar if it is present.  
  72.         getMenuInflater().inflate(R.menu.main, menu);  
  73.         return true;  
  74.     }  
  75.   
  76.     @Override  
  77.     public boolean onOptionsItemSelected(MenuItem item) {  
  78.         // Handle action bar item clicks here. The action bar will  
  79.         // automatically handle clicks on the Home/Up button, so long  
  80.         // as you specify a parent activity in AndroidManifest.xml.  
  81.         int id = item.getItemId();  
  82.         if (id == R.id.action_settings) {  
  83.             return true;  
  84.         }  
  85.         return super.onOptionsItemSelected(item);  
  86.     }  
  87. }  

 

 

 

主Activity比较简单,没什么好说的。

最后的是布局文件activity_main.xml:

 

[html] view plain copy
 
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     xmlns:myview="http://schemas.android.com/apk/res-auto"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:paddingBottom="@dimen/activity_vertical_margin"  
  7.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  8.     android:paddingRight="@dimen/activity_horizontal_margin"  
  9.     android:paddingTop="@dimen/activity_vertical_margin"  
  10.     tools:context="com.example.mycircleprogressdemo.MainActivity" >  
  11.   
  12.     <com.example.myview.MyCircleProgress   
  13.         android:id="@+id/my_circleprogress"  
  14.         android:layout_width="200dip"  
  15.         android:layout_height="200dip"  
  16.         myview:circle_width="20"  
  17.         myview:progress="0"  
  18.         />  
  19.       
  20. </RelativeLayout>  


这里要用到自定义属性,因此不要忘了在RelativeLayout中加入一行xmlns:myview="http://schemas.android.com/apk/res-auto",这样我们就可以用自定义属性了。其实我们定义自定义属性的时候也可以把圆环的颜色也自定义上去,这样我们就可以随我们的喜欢让环形进度条显现各种颜色了。大家不妨去试试。

 

 

 

好了,最后的最后附上源码下载地址:

源码下载

分类:

技术点:

相关文章:

  • 2022-01-03
  • 2021-09-15
  • 2021-08-05
  • 2021-10-25
  • 2021-12-27
  • 2022-12-23
  • 2021-12-29
猜你喜欢
  • 2021-07-28
  • 2023-04-04
  • 2021-05-02
  • 2021-11-07
  • 2022-02-05
  • 2021-06-17
相关资源
相似解决方案