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

Android 自定义View实现圆形进度条 深入理解onDraw和onMeasure及自定义属性

2017-06-23 17:45 831 查看
Android的View类是用户接口的基础构件,表示屏幕上的一块矩形区域,负责这个区域的绘制和事件处理。自定义View的过程主要包括重写onDraw及onMeasure方法 , 其中onMeasure方法的作用就是计算出自定义View的宽度和高度。这个计算的过程会参照父布局给出的大小(widthMeasureSpec和heightMeasureSpec),以及自己特点算出结果 ;onDraw则根据onMeasure测量后的宽高进行界面的绘制。onDraw主要用到两个类,Canvas和Paint。Canvas画布,相当于现实中画图用的纸或布;Paint画笔,相当于现实中的笔,基本方法有 drawLine 绘制直线 ,drawRect绘制矩形 , drawCirlce绘制圆形。

自定义圆形进度条效果如下



完整代码:

package com.circleprogress;

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;

/**
* Created by Administrator on 2017/6/22.
*/

public class CirlceView extends View {

//定义第一支画笔,画背景的圆
private Paint mPaintBackCircle;
//定义第二支画笔,画前景色的圆(进度条的环)
private Paint mPaintFrontCircle;

//定义绘制文字的画笔
private Paint mPaintText;

//定义环的宽度
private float mStrokeWidth = 50 ;
private float mhalfStrokeWidth = mStrokeWidth/2;

//定义圆心坐标和半径
private float mX = 200 + mhalfStrokeWidth ;
private float mY = 200 + mhalfStrokeWidth ;

private float mRadius = 200 ;

//定义矩形
private RectF mRectF ;

//开始进度
private int mProgress = 0 ;
//目标进度
private int mTargetProgress = 70 ;
//最大进度
private int mMax = 100 ;

//定义view的宽高
private int mWidth ;
private int mHeight ;

//默认半径
private static final int DEFAULT_RADIUS = 200 ;
private static final int DEFAULT_STROKE_WIDTH = 50 ;

public CirlceView(Context context) {
this(context,null);
}

public CirlceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

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

//获取自定义属性
if( attrs != null ){
TypedArray array  = context.obtainStyledAttributes(attrs , R.styleable.CirlceView);

mRadius = array.getDimensionPixelSize(R.styleable.CirlceView_radius , DEFAULT_RADIUS);
mStrokeWidth = array.getDimensionPixelSize(R.styleable.CirlceView_stroke_width,DEFAULT_STROKE_WIDTH);

array.recycle();
}
init();
}

private void initRect(){

if(mRectF == null ){
mRectF = new RectF();
int viewSize = (int) (mRadius*2);

int left = (mWidth - viewSize)/2 ;
int top = (mHeight - viewSize)/2 ;
int right = left + viewSize ;
int bottom = top + viewSize ;
mRectF.set(left,top,right,bottom);
}
}

//初始化画笔
private void init(){
mPaintBackCircle = new Paint();
//设置颜色
mPaintBackCircle.setColor(Color.WHITE);
//设置防锯齿
mPaintBackCircle.setAntiAlias(true);
//设置为空心
mPaintBackCircle.setStyle(Paint.Style.STROKE);
mPaintBackCircle.setStrokeWidth(mStrokeWidth);

mPaintFrontCircle = new Paint();
mPaintFrontCircle.setColor(0xFF66C796);
mPaintFrontCircle.setAntiAlias(true);
mPaintFrontCircle.setStyle(Paint.Style.STROKE);
mPaintFrontCircle.setStrokeWidth(mStrokeWidth);

mPaintText = new Paint();
mPaintText.setColor(0xFF66C796);
mPaintText.setAntiAlias(true);
mPaintText.setTextSize(50);
//设置文字居中
mPaintText.setTextAlign(Paint.Align.CENTER);
}

@Override
protected void onDraw(Canvas canvas) {

initRect();
//获取进度百分比
float angle = mProgress/(float)mMax * 360 ;

canvas.drawCircle(mWidth/2 , mHeight/2 , mRadius , mPaintBackCircle );
canvas.drawArc(mRectF , -90 , angle , false ,mPaintFrontCircle);
canvas.drawText(mProgress+"%", mWidth/2  , mHeight/2 , mPaintText);

if( mProgress < mTargetProgress) {
//更新进度
mProgress += 2;
//通知重新绘制
invalidate();
}
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

//测量宽高
mWidth = getRealSize(widthMeasureSpec);
mHeight = getRealSize(heightMeasureSpec);

//保存测量的宽高
setMeasuredDimension(mWidth,mHeight);
}

//测量View的真实尺寸
public int getRealSize( int measureSpec ){

int result = -1 ;

int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);

if( mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED){
//自己计算
result = (int) (mRadius * 2 + mStrokeWidth);
}else {
result = size ;
}

return result;
}
}


在values目录下新建attrs.xml文件 , 增加自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CirlceView">
<attr name="radius" format="dimension"></attr>
<attr name="stroke_width" format="dimension"></attr>
<attr name="back_circle_color" format="color"></attr>
<attr name="front_arc_color" format="color"></attr>
<attr name="text_visibility" format="boolean"></attr>
</declare-styleable>

</resources>


最后在布局文件中引入,设置自定义宽高和半径

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.circleprogress.MainActivity">

<com.circleprogress.CirlceView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:radius="100dp"
app:stroke_width="20dp"/>
</RelativeLayout>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐