前言
最近看到华为手机的系统天气软件里面有个弧形的进度条,感觉挺好玩,也比较简单,所以想自己写写代码来一个山寨版的。有不足之处欢迎大佬指正。
先看一下华为系统天气软件的截图:
想要实现的是空气质量和舒适度那个弧形的进度条。
看一下最终的效果:
看下代码实现:
package com.example.selfdefinitionview.custom;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.example.selfdefinitionview.R;
import com.example.selfdefinitionview.util.UiUtils;
/**
* @ClassName :MyRoundView
* @Description :
* @Author : SheYi
* @Date :2020/8/10 8:19 PM
*/
public class MyRoundView extends View {
private Paint circleBgPaint;
private int mProgress=0;
Handler handler=new Handler(Looper.getMainLooper());
private Paint circlePaint;
private Paint textPaint;
/*总的进度*/
private int totalProgress=100;
/*进度文字距离顶部的距离*/
private int textTopMargin=60;
/*圆环的宽度*/
private float circleBorderWidth;
/*圆环的背景色*/
private int circleBgColor;
/*圆环的颜色*/
private int circleColor;
/*设置圆心文字*/
private String centerText=null;
private Rect rect;
private Paint centerTextPaint;
private Context context;
/*默认的圆弧的线宽,单位为dp*/
private final int DEFULT_CIRCLE_BORDER_WIDTH=10;
public MyRoundView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context=context;
initAttrs(context,attrs);
init();
}
public MyRoundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context=context;
initAttrs(context,attrs);
init();
}
public MyRoundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
this.context=context;
initAttrs(context,attrs);
init();
}
private void initAttrs(Context context, @Nullable AttributeSet attrs){
TypedArray mTypeArray=context.obtainStyledAttributes(attrs, R.styleable.MyRoundView);
circleBorderWidth=mTypeArray.getDimension(R.styleable.MyRoundView_circleBorderWidth, UiUtils.convertDpToPixel(DEFULT_CIRCLE_BORDER_WIDTH,context));
circleBgColor=mTypeArray.getColor(R.styleable.MyRoundView_circleBgColor, getResources().getColor(R.color.color_F5));
circleColor=mTypeArray.getColor(R.styleable.MyRoundView_circleColor, Color.RED);
mTypeArray.recycle();
}
private void init(){
/*初始化圆弧底部背景画笔*/
circleBgPaint = new Paint();
circleBgPaint.setStyle(Paint.Style.STROKE);
circleBgPaint.setStrokeWidth(circleBorderWidth);
circleBgPaint.setAntiAlias(true);
circleBgPaint.setColor(circleBgColor);
circleBgPaint.setStrokeCap(Paint.Cap.ROUND);
/*初始化圆弧画笔*/
circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeWidth(circleBorderWidth);
circlePaint.setColor(circleColor);
circlePaint.setStrokeCap(Paint.Cap.ROUND);
/*初始化文字画笔*/
textPaint = new Paint();
textPaint.setStyle(Paint.Style.FILL);
textPaint.setAntiAlias(true);
textPaint.setTextSize(66);
textPaint.setColor(Color.BLACK);
/*初始化圆心文字画笔*/
centerTextPaint = new Paint();
centerTextPaint.setStyle(Paint.Style.FILL);
centerTextPaint.setAntiAlias(true);
centerTextPaint.setTextSize(66);
centerTextPaint.setColor(Color.BLACK);
rect = new Rect();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (mProgress<100){
mProgress=mProgress+2;
setProgress(mProgress);
handler.postDelayed(this,10);
}
}
},0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int finalWidth=getFinalWidth(widthMeasureSpec);
int finalHeight=getFinalHeigh(heightMeasureSpec);
setMeasuredDimension(finalWidth,finalHeight);
}
/**
* 测量View的宽度
* @param widthMeasureSpec
* @return
*/
private int getFinalWidth(int widthMeasureSpec){
int mode=MeasureSpec.getMode(widthMeasureSpec);
int size=MeasureSpec.getSize(widthMeasureSpec);
if (mode==MeasureSpec.AT_MOST){
size=0;
}
return size;
}
/**
* 测量View的高度
* @param heightMeasureSpec
* @return
*/
private int getFinalHeigh(int heightMeasureSpec){
int mode=MeasureSpec.getMode(heightMeasureSpec);
int size=MeasureSpec.getSize(heightMeasureSpec);
if (mode==MeasureSpec.AT_MOST){
size=0;
}
return size;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int minValue=getMeasuredWidth()<getMeasuredHeight()?getMeasuredWidth():getMeasuredHeight();
float radius=minValue/2-circleBorderWidth/2;
/*画圆弧背景*/
canvas.drawArc(circleBorderWidth/2,circleBorderWidth/2,circleBorderWidth/2+2*radius,circleBorderWidth/2+2*radius,135,270,false,circleBgPaint);
/*画圆弧*/
canvas.drawArc(circleBorderWidth/2,circleBorderWidth/2,circleBorderWidth/2+2*radius,circleBorderWidth/2+2*radius,135,270*mProgress/totalProgress,false,circlePaint);
/*画当前进度文字*/
canvas.save();
canvas.translate(circleBorderWidth/2+radius,circleBorderWidth/2+radius);
String currentProgressStr=String.valueOf(mProgress);
rect.setEmpty();
textPaint.getTextBounds(currentProgressStr,0,currentProgressStr.length(),rect);
float x1= (float) (-radius*Math.cos(Math.PI*45/180f));
float y1= (float) (radius*Math.sin(Math.PI*45/180f));
float X1=x1-(rect.width()>>1);
float Y1=y1+(rect.height()>>1)+textTopMargin;
canvas.drawText(currentProgressStr, X1, Y1, textPaint);
/*画总进度文字*/
String totalProgressStr=String.valueOf(totalProgress);
rect.setEmpty();
textPaint.getTextBounds(totalProgressStr,0,totalProgressStr.length(),rect);
float x2= (float) (radius*Math.cos(Math.PI*45/180f));
float y2= (float) (radius*Math.sin(Math.PI*45/180f));
float X2=x2-(rect.width()>>1);
float Y2=y2+(rect.height()>>1)+textTopMargin;
canvas.drawText(totalProgressStr, X2, Y2, textPaint);
String centerTextStr="";
if (TextUtils.isEmpty(centerText)){
centerTextStr=mProgress*100/totalProgress+"%";
}else{
centerTextStr=centerText;
}
rect.setEmpty();
textPaint.getTextBounds(centerTextStr,0,centerTextStr.length(),rect);
float X3=-(rect.width()>>1);
float Y3=(rect.height()>>1);
canvas.drawText(centerTextStr, X3, Y3, centerTextPaint);
canvas.restore();
}
public void setProgress(int progress){
this.mProgress=progress;
invalidate();
}
}
属性:
<!--MyRoundView用到的属性-->
<declare-styleable name="MyRoundView">
<attr name="circleBorderWidth" format="dimension"></attr>
<attr name="circleBgColor" format="color"></attr>
<attr name="circleColor" format="color"></attr>
</declare-styleable>
在xml布局中使用:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible">
<com.example.selfdefinitionview.custom.MyRoundView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>