今天給大家带来的是自定义环形进度条的实现。虽然网上有各种方法实现环形进度条,但是我还是忍不住想写一下。
还是先看看效果吧!
当然我们也可以设置它的大小和圆环的宽度:
哈哈,是不是很有趣哩!接下来我们就看看是怎么实现的吧!
新建一个名为MyCircleProgressDemo的Android工程项目,目录如下:
首先得考虑该自定义View需要哪些属性,因此要在values目录下新建名为attrs.xml的文件用于自定义的属性:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="myattrs">
- <attr name="circle_width" format="integer"/><!-- 自定义属性 circle_width 表示圆环的宽度-->
- <attr name="radius" format="integer"/><!-- 自定义属性 radius 表示圆环的半径-->
- <attr name="progress" format="integer"/><!-- 自定义属性 progress 表示圆环进度的初始值-->
- <attr name="max" format="integer"/><!-- 自定义属性 max 表示圆环进度的最大值-->
- </declare-styleable>
- </resources>
在attrs.xml文件中我们定义了四个属性。他们分别表示圆环的宽度,圆环的半径,圆环进度的初始值和圆环进度的最大值。
接下来就是自定义圆环的实现MyCircleProgress.Java:
- package com.example.myview;
- import com.example.mycircleprogressdemo.R;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.RectF;
- import android.util.AttributeSet;
- import android.view.View;
- /**
- * @author Joker_Ya
- */
- public class MyCircleProgress extends View {
- private int progress;
- // 设置最大值
- private int max;
- // 圓環寬度
- private int circleWidth;
- // 控件的寬度
- private int width;
- // 控件的高度
- private int height;
- // 默認圓的半徑
- private int radius;
- // 绘制轨迹的画笔
- private Paint paint;
- // 绘制填充的画笔
- private Paint fillpaint;
- private RectF oval;
- // View重绘标志
- private boolean reset = false;
- // 设置监听
- private ProgressChangeListener listener = null;
- public MyCircleProgress(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- // 获得自定义属性
- TypedArray mArray = context.obtainStyledAttributes(attrs,
- R.styleable.myattrs);
- // 获得自定义属性的初始进度属性,否则返回0
- progress = mArray.getInteger(R.styleable.myattrs_progress, 0);
- // 获得自定义属性的最大进度值属性,否则返回100
- max = mArray.getInteger(R.styleable.myattrs_max, 100);
- // 获得自定义属性的圆环宽度属性,否则返回20
- circleWidth = mArray.getInteger(R.styleable.myattrs_circle_width, 20);
- // 获得自定义属性的半径属性,否则返回120
- radius = mArray.getInteger(R.styleable.myattrs_radius, 120);
- paint = new Paint();
- // 抗锯齿
- paint.setAntiAlias(true);
- // 帮助抗锯齿
- paint.setFlags(Paint.ANTI_ALIAS_FLAG);
- // 设置样式为空心
- paint.setStyle(Paint.Style.STROKE);
- paint.setDither(true);
- paint.setStrokeJoin(Paint.Join.ROUND);
- fillpaint = new Paint();
- // 抗锯齿
- fillpaint.setAntiAlias(true);
- // 帮助抗锯齿
- fillpaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- // 设置样式为空心
- fillpaint.setStyle(Paint.Style.STROKE);
- fillpaint.setDither(true);
- fillpaint.setStrokeJoin(Paint.Join.ROUND);
- oval = new RectF();
- // 回收mArray
- mArray.recycle();
- }
- @Override
- protected void onDraw(Canvas canvas) {
- // TODO Auto-generated method stub
- super.onDraw(canvas);
- if (reset) {
- canvas.drawColor(Color.TRANSPARENT);
- reset = false;
- }
- // 获得组件的宽高
- width = getMeasuredWidth();
- height = getMeasuredHeight();
- // 获得半径
- radius = width / 2 - circleWidth;
- // 设置画笔颜色
- paint.setColor(Color.GREEN);
- // 设置画笔宽度
- paint.setStrokeWidth(circleWidth);
- // 中心画圆
- canvas.drawCircle(width / 2, height / 2, radius, paint);
- /* 绘制边线 */
- // 画笔宽度
- paint.setStrokeWidth(1f);
- // 边线颜色
- paint.setColor(Color.BLACK);
- canvas.drawCircle(width / 2, height / 2, radius + circleWidth / 2
- + 0.5f, paint);
- canvas.drawCircle(width / 2, height / 2, radius - circleWidth / 2
- - 0.5f, paint);
- // 设置填充画笔的类型,边角是圆角的
- fillpaint.setStrokeCap(Paint.Cap.ROUND);
- // 画笔宽度
- fillpaint.setStrokeWidth(circleWidth);
- // 设置左上角和右下角坐标
- oval.set(width / 2 - radius, height / 2 - radius, width / 2 + radius,
- height / 2 + radius);
- // 绘制圆弧。第二个参数为起始角度,第三个为跨越的角度,第三個为实心,true为实心,false为空心
- canvas.drawArc(oval, -90, ((float) progress / max) * 360, false,
- fillpaint);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // TODO Auto-generated method stub
- int width = View.MeasureSpec.getSize(widthMeasureSpec);
- int height = View.MeasureSpec.getSize(heightMeasureSpec);
- setMeasuredDimension(width, height);
- }
- // 定义接口ProgressChangeListener
- public interface ProgressChangeListener {
- public void ProgressChange(int progress1);
- public void onComplete(int progress2);
- }
- public void setProgressChangeListener(ProgressChangeListener listener) {
- // TODO Auto-generated method stub
- this.listener = listener;
- }
- // 设置进度
- public void setProgress(int progress) {
- this.progress = progress;
- this.invalidate();
- if (listener != null) {
- if (this.max <= this.progress) {
- listener.onComplete(progress);
- } else {
- listener.ProgressChange(progress);
- }
- }
- }
- // 重置进度
- public void reset() {
- reset = true;
- progress = 0;
- // 重绘
- invalidate();
- }
- }
代码里的注释很详细了,在这就简单的说一下:得到控件的宽高-->得到中心点-->以中心点为坐标画圆环-->给圆环内外加上表框-->根据progress绘制圆弧。大概就是这样吧!
然后是MainActivity.java:
- package com.example.mycircleprogressdemo;
- import com.example.myview.MyCircleProgress;
- import com.example.myview.MyCircleProgress.ProgressChangeListener;
- import android.support.v7.app.ActionBarActivity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.Menu;
- import android.view.MenuItem;
- /**
- * @author Joker_Ya
- */
- public class MainActivity extends ActionBarActivity {
- private MyCircleProgress myCircleProgress;
- private int progress = 0;
- private Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // TODO Auto-generated method stub
- switch (msg.what) {
- case 0x123:
- addProgress();
- break;
- default:
- break;
- }
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- myCircleProgress = (MyCircleProgress) findViewById(R.id.my_circleprogress);
- // 设置监听
- myCircleProgress
- .setProgressChangeListener(new ProgressChangeListener() {
- @Override
- public void ProgressChange(int progress1) {
- // TODO Auto-generated method stub
- }
- @Override
- public void onComplete(int progress2) {
- // TODO Auto-generated method stub
- progress = 0;
- // 重置进度
- myCircleProgress.reset();
- }
- });
- addProgress();
- }
- // 该方法让progress每次加上10
- public void addProgress() {
- progress += 10;
- myCircleProgress.setProgress(progress);
- handler.sendEmptyMessageDelayed(0x123, 1000);
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
- if (id == R.id.action_settings) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
- }
主Activity比较简单,没什么好说的。
最后的是布局文件activity_main.xml:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- xmlns:myview="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context="com.example.mycircleprogressdemo.MainActivity" >
- <com.example.myview.MyCircleProgress
- android:id="@+id/my_circleprogress"
- android:layout_width="200dip"
- android:layout_height="200dip"
- myview:circle_width="20"
- myview:progress="0"
- />
- </RelativeLayout>
这里要用到自定义属性,因此不要忘了在RelativeLayout中加入一行xmlns:myview="http://schemas.android.com/apk/res-auto",这样我们就可以用自定义属性了。其实我们定义自定义属性的时候也可以把圆环的颜色也自定义上去,这样我们就可以随我们的喜欢让环形进度条显现各种颜色了。大家不妨去试试。
好了,最后的最后附上源码下载地址: