其他分享
首页 > 其他分享> > Android自定义view流程

Android自定义view流程

作者:互联网

 

Android自定义view流程,主要目的是总结实现过程中的思路以及一些需要注意的地方。
首先,我们先来看一张效果图:

实现逻辑

知识点

onMeasure

setMeasuredDimension

Canvas#drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

onDraw

主要代码

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 根据父控件传递的widthMeasureSpec和heightMeasureSpec调用MeasureSpec.getSize测量自身宽高
    int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
    int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
    int finalWidth = measureWidth;
    int finalHeight = measureHeight;
    // 根据自身宽高重新计算新的宽高,使新的宽高比为2:1
    if (measureWidth >= measureHeight * 2) {
        finalWidth = measureHeight * 2;
    } else {
        finalHeight = measureWidth / 2;
    }
    // 设置View新的宽高
    setMeasuredDimension(finalWidth, finalHeight);
}

/**
 * 绘制圆弧
 * @param canvas
 * @param progress 进度
 * @param color 进度颜色
 * @param radius 圆弧半径
 */
private void drawArc(Canvas canvas, float progress, int color, float radius){
    // 圆心
    mXCenter = getWidth() / 2;
    mYCenter = getHeight() ;

    mPaint.setColor(mBackgroundArcColor);
    // 构造边界矩形
    RectF oval = new RectF();
    oval.left = (mXCenter - radius);
    oval.top = (mYCenter - radius);
    oval.right = mXCenter + radius;
    oval.bottom = radius * 2 + (mYCenter - radius);
    //绘制圆弧背景
    canvas.drawArc(oval, -180, 180, false, mPaint);

    //绘制圆弧进度
    float showDegree = progress / 100 * 180;
    mPaint.setColor(color);
    canvas.drawArc(oval, -180, showDegree, false, mPaint);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    // 初始半径
    float originalRadius = getWidth() * .5f;
    // 画笔半宽
    float halfArcStokeWidth = mArcStrokeWidth * .5f;

    // 外圆环半径=初始半径-画笔半宽
    float outSideArcRadius = originalRadius - halfArcStokeWidth;
    drawArc(canvas, mOutsideProgress, mOutsideArcColor, outSideArcRadius);

    // 中圆环半径=外圆的半径-圆环偏移值-画笔半宽
    float middleArcRadius = outSideArcRadius - mArcOffset - halfArcStokeWidth;
    drawArc(canvas, mMiddleProgress, mMiddleArcColor, middleArcRadius);

    // 内圆环半径=中圆的半径-圆环偏移值-画笔半宽
    float insideArcRadius = middleArcRadius - mArcOffset - halfArcStokeWidth;
    drawArc(canvas, mInsideProgress, mInsideArcColor, insideArcRadius);
}

全部代码

ThreeArcView.java

public class ThreeArcView extends View {

    //圆弧画笔
    private Paint mPaint;
    //背景圆环颜色
    private int mBackgroundArcColor;
    //外圆环颜色
    private int mOutsideArcColor;
    //中圆环颜色
    private int mMiddleArcColor;
    //内圆环颜色
    private int mInsideArcColor;
    //外圆展示弧度
    private float mOutsideProgress;
    //中圆展示弧度
    private float mMiddleProgress;
    //内圆展示弧度
    private float mInsideProgress;
    //圆弧宽度
    private float mArcStrokeWidth;
    //圆偏移值
    private float mArcOffset;

    // 圆心x坐标
    private int mXCenter;
    // 圆心y坐标
    private int mYCenter;

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

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

    public ThreeArcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initVariable();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ThreeArcView, 0, 0);
        mArcStrokeWidth = typeArray.getDimension(R.styleable.ThreeArcView_ts_strokeWidth, dp2px(context, 20));
        // 圆环背景颜色
        mBackgroundArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_bgArcColor, 0xFFFFFFFF);
        // 圆环颜色
        mOutsideArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_outsideBgColor, 0xFFFFFFFF);
        mMiddleArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_middleBgColor, 0xFFFFFFFF);
        mInsideArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_insideBgColor, 0xFFFFFFFF);
        // 圆进度
        mOutsideProgress = typeArray.getFloat(R.styleable.ThreeArcView_ts_outsideProgress, 0f);
        mMiddleProgress = typeArray.getFloat(R.styleable.ThreeArcView_ts_middleProgress, 0f);
        mInsideProgress = typeArray.getFloat(R.styleable.ThreeArcView_ts_insideProgress, 0f);
        // 圆环偏移值
        mArcOffset = typeArray.getDimension(R.styleable.ThreeArcView_ts_radiusOffset, dp2px(context, 20));
        typeArray.recycle();

        // 偏移值不能小于画笔宽度的一半,否则会发生覆盖
        if (mArcOffset < mArcStrokeWidth / 2){
            mArcOffset = mArcStrokeWidth / 2;
        }
    }

    private void initVariable() {
        //背景圆弧画笔设置
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mArcStrokeWidth);
        mPaint.setStrokeCap(Paint.Cap.ROUND);//开启显示边缘为圆形
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 分别获取期望的宽度和高度,并取其中较小的尺寸作为该控件的宽和高
        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        //裁剪出一个 (宽:高) = (2:1) 的矩形
        int finalWidth = measureWidth;
        int finalHeight = measureHeight;
        if (measureWidth >= measureHeight * 2) {
            finalWidth = measureHeight * 2;
        } else {
            finalHeight = measureWidth / 2;
        }
        setMeasuredDimension(finalWidth, finalHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 初始半径
        float originalRadius = getWidth() * .5f;
        // 画笔半宽
        float halfArcStokeWidth = mArcStrokeWidth * .5f;

        // 外圆环半径=初始半径-画笔半宽
        float outSideArcRadius = originalRadius - halfArcStokeWidth;
        drawArc(canvas, mOutsideProgress, mOutsideArcColor, outSideArcRadius);

        // 中圆环半径=外圆的半径-圆环偏移值-画笔半宽
        float middleArcRadius = outSideArcRadius - mArcOffset - halfArcStokeWidth;
        drawArc(canvas, mMiddleProgress, mMiddleArcColor, middleArcRadius);

        // 内圆环半径=中圆的半径-圆环偏移值-画笔半宽
        float insideArcRadius = middleArcRadius - mArcOffset - halfArcStokeWidth;
        drawArc(canvas, mInsideProgress, mInsideArcColor, insideArcRadius);
    }

    /**
     * 绘制圆弧
     * @param canvas
     * @param progress 进度
     * @param color 进度颜色
     * @param radius 圆弧半径
     */
    private void drawArc(Canvas canvas, float progress, int color, float radius){
        // 圆心
        mXCenter = getWidth() / 2;
        mYCenter = getHeight() ;

        mPaint.setColor(mBackgroundArcColor);
        // 构造边界矩形
        RectF oval = new RectF();
        oval.left = (mXCenter - radius);
        oval.top = (mYCenter - radius);
        oval.right = mXCenter + radius;
        oval.bottom = radius * 2 + (mYCenter - radius);
        //绘制圆弧背景
        canvas.drawArc(oval, -180, 180, false, mPaint);

        //绘制圆弧进度
        float showDegree = progress / 100 * 180;
        mPaint.setColor(color);
        canvas.drawArc(oval, -180, showDegree, false, mPaint);
    }

    private void setOutSideProgress(float progress){
        this.mOutsideProgress = progress;
        postInvalidate();
    }

    private void setMiddleProgress(float progress){
        this.mMiddleProgress = progress;
        postInvalidate();
    }

    private void setInsideProgress(float progress){
        this.mInsideProgress = progress;
        postInvalidate();
    }

    public void setProgress(float outSideProgress, float middleProgress, float insideProgress) {
        mOutsideProgress = outSideProgress;
        mMiddleProgress = middleProgress;
        mInsideProgress = insideProgress;
        postInvalidate();
    }

    public int dp2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    public int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

    public int px2sp(Context context, float pxValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }
}

styes.xml

<declare-styleable name="ThreeArcView">
    <!-- 画笔宽度 -->
    <attr name="ts_strokeWidth" format="dimension" />
    <!-- 圆弧背景色 -->
    <attr name="ts_bgArcColor" format="color" />
    <!-- 外圆进度颜色 -->
    <attr name="ts_outsideBgColor" format="color" />
    <!-- 中圆进度颜色 -->
    <attr name="ts_middleBgColor" format="color" />
    <!-- 内圆进度颜色 -->
    <attr name="ts_insideBgColor" format="color" />
    <!-- 外圆进度 -->
    <attr name="ts_outsideProgress" format="float" />
    <!-- 中圆进度 -->
    <attr name="ts_middleProgress" format="float" />
    <!-- 内圆进度 -->
    <attr name="ts_insideProgress" format="float" />
    <!-- 圆偏移值 -->
    <attr name="ts_radiusOffset" format="dimension" />
</declare-styleable>

OK,本文到此结束,若发现问题,欢迎一起留言一起探讨,感谢~

相关教程

Android基础系列教程:
Android基础课程U-小结_哔哩哔哩_bilibili
Android基础课程UI-布局_哔哩哔哩_bilibili
Android基础课程UI-控件_哔哩哔哩_bilibili
Android基础课程UI-动画_哔哩哔哩_bilibili
Android基础课程-activity的使用_哔哩哔哩_bilibili
Android基础课程-Fragment使用方法_哔哩哔哩_bilibili
Android基础课程-热修复/热更新技术原理_哔哩哔哩_bilibili

本文转自 https://juejin.cn/post/6847902216959819790,如有侵权,请联系删除。

标签:canvas,自定义,int,float,private,context,oval,Android,view
来源: https://www.cnblogs.com/322ww/p/15686586.html