您的位置:首页 > 移动开发 > Android开发

Android自定义View之圆形进度条

2016-04-08 23:05 411 查看

Android自定义View之圆形进度条

尽管github上的开源圆形进度条已经很多了,但是我仍然希望能通过自己完成一个,接下来我就一步一步实现圆形进度条,今天我们要实现的效果图如下:





观察上面两幅图我们可以看到,这个图形是由两部分组成的中间的圆形+外围的弧形,我们自然而然的想到了用canvas画。想好就开始实践,

新建PercentDigitalView项目,新建view包,新建PercentDigitalView继承自View,项目结构如下:



接下来我们在为PercentDigitalView添加构造函数,并重写onDraw方法,修改后完整代码如下:

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;
import android.view.ViewTreeObserver;

import com.tt.percentdigitalview.R;

/**
* Created by TuoZhaoBing on 2016/4/8 0007.
*/
public class PercentDigitalView extends View {

public static final String TAG = "PercentDigitalView";

public PercentDigitalView(Context context) {
super(context);
}

public PercentDigitalView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public PercentDigitalView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}


接着来的工作就是画圆和画弧了,添加画笔并进行画笔的初始化,如下两段代码:

private Paint mCirclePaint,mArcPaint,mTextPaint;


public void init(Context context,AttributeSet attrs){
mContext = context;
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setStyle(Paint.Style.FILL);
mTextPaint.setStyle(Paint.Style.FILL);
mArcPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setColor(Color.BLACK);
mCirclePaint.setColor(Color.GREEN);
mArcPaint.setColor(Color.GREEN);
}


另外我们要画圆,画弧肯定有圆心,圆的半径和弧的宽度,还有弧度的百分比,将这些定义好,并初始化,如下面两段代码:

private int mCircleX;
private float mRadius;
private int mTmpSweepValue =0,mSweepValue;
private RectF mInnerArcRectF;
public String mShowText = "%";
private int mWidth,mHeight;
private int mInnerArcWidth;


TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PercentDigitalView);
mRadius = ta.getInteger(R.styleable.PercentDigitalView_innerCircleRadius,100);
mInnerArcWidth = ta.getInteger(R.styleable.PercentDigitalView_ringWidth,50);
mSweepValue = ta.getInteger(R.styleable.PercentDigitalView_ringPercent,350);
ta.recycle();


这里我默认绘制圆心在该View的水平中心,所以我实现了
ViewTreeObserver.OnGlobalLayoutListener
具体的实现函数的代码如下:

@Override
public void onGlobalLayout() {
mWidth = getWidth();
mHeight = getHeight();
}


做好了准备工作,重点戏就来了,接下来我们在onDraw中进行圆,圆弧和字符的绘制,代码如下:

mCircleX = mWidth/2;
mInnerArcRectF = new RectF((float) (mWidth*0.1),
(float) (mWidth*0.1),
(float) (mWidth*0.9),
(float) (mWidth*0.9));
canvas.drawCircle(mCircleX,mCircleX,mRadius,mCirclePaint);
canvas.drawArc(mInnerArcRectF,270,mTmpSweepValue,false,mArcPaint);
java.text.DecimalFormat df=new java.text.DecimalFormat("#.##");
canvas.drawText(mShowText+(df.format(mTmpSweepValue*100/360d)),0,mShowText.length()+(df.format(mTmpSweepValue*100/360d)+"").length(),mCircleX,mCircleX+(mShowText.length()/4),mTextPaint);
if (mTmpSweepValue < mSweepValue){
mTmpSweepValue += 1;
postInvalidate();
}
super.onDraw(canvas);


至此,我们就完成了PercentDigitalView的全部编码,该类的完整代码如下:

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.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;

import com.tt.percentdigitalview.R;

/**
* Created by TuoZhaoBing on 2016/4/7 0007.
*/
public class PercentDigitalView extends View implements ViewTreeObserver.OnGlobalLayoutListener{

public static final String TAG = "PercentDigitalView";
private Context mContext;
private int mCircleX;
private float mRadius;
private int mTmpSweepValue =0,mSweepValue;
private RectF mInnerArcRectF;
private Paint mCirclePaint,mArcPaint,mTextPaint;
public String mShowText = "%";
private int mWidth,mHeight;
private int mInnerArcWidth;

public PercentDigitalView(Context context) {
super(context);
init(context,null);
}

public PercentDigitalView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}

public PercentDigitalView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}

public void init(Context context,AttributeSet attrs){
mContext = context;

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PercentDigitalView); mRadius = ta.getInteger(R.styleable.PercentDigitalView_innerCircleRadius,100); mInnerArcWidth = ta.getInteger(R.styleable.PercentDigitalView_ringWidth,50); mSweepValue = ta.getInteger(R.styleable.PercentDigitalView_ringPercent,350); ta.recycle();

mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setStyle(Paint.Style.FILL);
mTextPaint.setStyle(Paint.Style.FILL);
mArcPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setColor(Color.BLACK);
mCirclePaint.setColor(Color.GREEN);
mArcPaint.setColor(Color.GREEN);
mArcPaint.setStrokeWidth((float)(mInnerArcWidth));
getViewTreeObserver().addOnGlobalLayoutListener(this);
}

@Override
protected void onDraw(Canvas canvas) {
mCircleX = mWidth/2; mInnerArcRectF = new RectF((float) (mWidth*0.1), (float) (mWidth*0.1), (float) (mWidth*0.9), (float) (mWidth*0.9)); canvas.drawCircle(mCircleX,mCircleX,mRadius,mCirclePaint); canvas.drawArc(mInnerArcRectF,270,mTmpSweepValue,false,mArcPaint); java.text.DecimalFormat df=new java.text.DecimalFormat("#.##"); canvas.drawText(mShowText+(df.format(mTmpSweepValue*100/360d)),0,mShowText.length()+(df.format(mTmpSweepValue*100/360d)+"").length(),mCircleX,mCircleX+(mShowText.length()/4),mTextPaint); if (mTmpSweepValue < mSweepValue){ mTmpSweepValue += 1; postInvalidate(); } super.onDraw(canvas);
}

@Override
public void onGlobalLayout() {
mWidth = getWidth();
mHeight = getHeight();
}
}


完整项目源码下载地址:github
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: