首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Android 自定义圆形进度View

Android 自定义圆形进度View

作者头像
大话swift
发布于 2020-03-26 16:31:03
发布于 2020-03-26 16:31:03
1.1K0
举报
文章被收录于专栏:大话swift大话swift
在进行App开发过程中不免会需要自定

接下来我们来实现一个这样的基本显示效果,在进行前我们先来看看需要哪些基本知识:

1怎么使用attrs定义和获取属性

2 使用Paint画圆与文本绘制

3 认真分析UI的界面逻辑

一 attrs.xml定义属性

1 定义一个class继承自View

代码语言:javascript
复制

public class CirCleView extends View {


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

    public CirCleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CirCleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public CirCleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        
        }

2 在values下面创建一个attrs.xml资源文件

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CirCleView">
        <attr name="mBackCircleWidth" format="dimension" />
        <attr name="mBackCircleColor" format="color" />

        <attr name="mPercent" format="string" />
        <attr name="mPadding" format="dimension" />


        <attr name="mOuterCircleColorWitdth" format="dimension"/>
        <attr name="mOuterCircleColor" format="color" />


        <attr name="mTitle" format="string" />
        <attr name="mTitleTextSize" format="dimension" />
        <attr name="mTitleTextColor" format="color" />

    </declare-styleable>
</resources>

3 在自定义view中获取这些属性

代码语言:javascript
复制
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CirCleView);

        backCircleWidth = typedArray.getDimension(R.styleable.CirCleView_mBackCircleWidth, 1);
        backCircleColor = typedArray.getColor(R.styleable.CirCleView_mBackCircleColor, Color.parseColor("#ff0000"));

        outerCircleColor = typedArray.getColor(R.styleable.CirCleView_mOuterCircleColor, Color.parseColor("#00ff00"));
        outerCircleWidth = typedArray.getDimension(R.styleable.CirCleView_mOuterCircleColorWitdth, 2);

        mPadding = typedArray.getDimension(R.styleable.CirCleView_mPadding, 0);

        String mPercent = typedArray.getString(R.styleable.CirCleView_mPercent);
        currentPercent = Float.parseFloat(mPercent);


        title = typedArray.getString(R.styleable.CirCleView_mTitle);
        titleTextColor = typedArray.getColor(R.styleable.CirCleView_mTitleTextColor, Color.parseColor("#ffffff"));
        titleTextSize = typedArray.getDimension(R.styleable.CirCleView_mTitleTextSize, 20);

        typedArray.recycle();

获取属性中最后记得调用recycle

代码语言:javascript
复制
Recycles the TypedArray, to be re-used by a later caller. After calling
代码语言:javascript
复制
this function you must not ever touch the typed array again.

二 Paint的基本操作

1 根据获取的属性值或者class获取的默认值对Paint进行设置

代码语言:javascript
复制

        backCirclePaint = new Paint();
        backCirclePaint.setColor(backCircleColor);
        backCirclePaint.setAntiAlias(true);
        backCirclePaint.setStrokeWidth(backCircleWidth);
        backCirclePaint.setStyle(Paint.Style.STROKE);


        outerCirclePaint = new Paint();
        outerCirclePaint.setColor(outerCircleColor);
        outerCirclePaint.setAntiAlias(true);
        outerCirclePaint.setStrokeWidth(outerCircleWidth);
        outerCirclePaint.setStyle(Paint.Style.STROKE);
        outerCirclePaint.setStrokeCap(Paint.Cap.ROUND);


        mTitlePaint = new Paint();
        mTitlePaint.setTextSize(titleTextSize);
        mTitlePaint.setColor(titleTextColor);

2 在public void draw(Canvas canvas) 中完成操作绘制操作

无论是原的绘制还是文本的绘制首先我们要计算他们的位置,而要计算这些我们需要调用系统提供的测绘方法获取宽高并保存下来留待后续使用

代码语言:javascript
复制
 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
    }

2.1 底层圆的绘制

底层的圆作为衬托的背景,为了烘托出后续我们的进度弧形,因此它是一个整圆

代码语言:javascript
复制

//        画圆
        float backCircleR = (Math.min(width, height) - 2 * mPadding) / 2;
        canvas.drawCircle(width / 2, height / 2, backCircleR, backCirclePaint);

思路很简单我们去除padding之后算出圆心和半径直接画圆即可。

此处唯一需要注意的细节是半径的处理要取宽高的最小值

2.2 进度圆的绘制

代码语言:javascript
复制
 //画进度圆弧
        RectF rectF = new RectF(mPadding, mPadding, width - mPadding, height - mPadding);
        //顺时针走,从水平最左侧开始也就是3点钟方位为0起点
        canvas.drawArc(rectF, -90, 360 * currentPercent, false, outerCirclePaint);

其实这里已经不能完全称之为圆,因为我们是画弧线而圆是进度达到100%的一种表现形式而已。这里其实是有一个大坑的----在我们数学中是按照象限沿着逆时针来走的而此处却跟我们的常识有出入:从我们钟表上的3点位置顺时针作为起点开始

2.3 指示文本的绘制

文本绘制这个逻辑其实也算是比较简单的,我们要根据文本的长度和字体来算出它所占用的空间大小最后在View的width和height的限定下房到何时位置即可

代码语言:javascript
复制
  Rect titleRect = new Rect();
        mTitlePaint.getTextBounds(title, 0, title.length(), titleRect);
        canvas.drawText(title, width / 2 - titleRect.width() / 2, height / 4 + titleRect.height() / 2, mTitlePaint);

        DecimalFormat df = new DecimalFormat("#%");//乘以100后以百分比形式输出,此处输出"12%"

        String percentMsg =  df.format(currentPercent);
//        percentMsg = String.valueOf(currentPercent * 100) + "%";

        mTitlePaint.getTextBounds(percentMsg, 0, percentMsg.length(), titleRect);
        canvas.drawText(percentMsg, width / 2 - titleRect.width() / 2, height / 2 + titleRect.height() / 2, mTitlePaint);

这里我们对于小数的计算遇到了点麻烦

此时设置的进度为0.3

代码语言:javascript
复制
<com.example.androidgo.CirCleView
        android:background="@color/RGB_E6E9ED"
        android:layout_width="200dp"
        app:mBackCircleColor="@color/colorAccent"
        app:mBackCircleWidth="@dimen/px_to_dip_12"
        app:mOuterCircleColor="@color/RGB_FF8209"
        app:mOuterCircleColorWitdth="10dp"
        app:mPadding="5dp"
        app:mPercent="0.3"
        app:mTitleTextColor="@color/colorPrimaryDark"
        app:mTitleTextSize="20sp"
        app:mTitle="当前进度"
        android:layout_height="200dp" />

大家可以把进行绘制处的percentMsg的转化注释打开看看效果,也可以看看

DecimalFormat的使用

长按二维吗查看源代码

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-15,如有侵权请联系 cloudcommunity@tencent.com 删除
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档