|
Android 自定义View实现圆形进度条
深入理解onDraw和onMeasure及自定义属性 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> |
----------------------------
原文链接:https://blog.csdn.net/SakuraMashiro/article/details/73650592
程序猿的技术大观园:www.javathinker.net
[这个贴子最后由 flybird 在 2020-03-09 22:39:50 重新编辑]
|
|