自定义View,仿华为天气弧形进度条

前言

最近看到华为手机的系统天气软件里面有个弧形的进度条,感觉挺好玩,也比较简单,所以想自己写写代码来一个山寨版的。有不足之处欢迎大佬指正。

先看一下华为系统天气软件的截图:
在这里插入图片描述

想要实现的是空气质量和舒适度那个弧形的进度条。
看一下最终的效果:
在这里插入图片描述

看下代码实现:

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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值