Android自定义View之实现环形进度条


转载请注明出处:http://blog.csdn.net/joker_ya/article/details/40585283

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

还是先看看效果吧!

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

 

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


新建一个名为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",这样我们就可以用自定义属性了。其实我们定义自定义属性的时候也可以把圆环的颜色也自定义上去,这样我们就可以随我们的喜欢让环形进度条显现各种颜色了。大家不妨去试试。


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

源码下载


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值