自定义View圆环

Posted 随笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义View圆环相关的知识,希望对你有一定的参考价值。

//自定义View类

public class MyRoundProcess extends View {

    /**
     * 自定义属性:
     * <p/>
     * 1. 外层圆的颜色 roundColor
     * <p/>
     * 2. 弧形进度圈的颜色 rouncProgressColor
     * <p/>
     * 3. 中间百分比文字的颜色 textColor
     * <p/>
     * 4. 中间百分比文字的大小 textSize
     * <p/>
     * 5. 圆环的宽度(以及作为弧形进度的圆环宽度)
     * <p/>
     * 6. 圆环的风格(Paint.Style.FILL  Paint.Syle.Stroke)
     */


    private static final String TAG = "MyRoundProcess";

    private int mWidth;
    private int mHeight;

    private Paint mPaint;
    private Paint mTextPaint;

    private float progress = 0f;
    private final float maxProgress = 100f; // 不可以修改的最大值

    //region 自定义属性的值
    int roundColor;
    int roundProgressColor;
    int textColor;
    float textSize;
    //endregion

    // 画笔的粗细(默认为40f, 在 onLayout 已修改)
    private float mStrokeWidth = 40f;
    private ValueAnimator mAnimator;
    private float mLastProgress = -1;

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

    public MyRoundProcess(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRoundProcess(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        // 初始化属性
        initAttrs(context, attrs, defStyleAttr);

        // 初始化点击事件
        initClickListener();
    }

    /**
     * 初始化属性
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray a = null;
        try {
            a = context.obtainStyledAttributes(attrs, R.styleable.MyRoundProcess);

            roundColor = a.getColor(R.styleable.MyRoundProcess_roundColor, getResources().getColor(android.R.color.darker_gray));
            roundProgressColor = a.getColor(R.styleable.MyRoundProcess_roundProgressColor, getResources().getColor(android.R.color.holo_red_dark));
            textColor = a.getColor(R.styleable.MyRoundProcess_textColor, getResources().getColor(android.R.color.holo_blue_dark));
            textSize = a.getDimension(R.styleable.MyRoundProcess_textSize, 22f);

        } finally {
            // 注意,别忘了 recycle
            a.recycle();
        }
    }

    /**
     * 初始化点击事件
     */
    private void initClickListener() {
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                // 重新开启动画
                restartAnimate();
            }
        });
    }

    /**
     * 当开始布局时候调用
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        // 获取总的宽高
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();

        // 初始化各种值
        initValue();

        // 设置圆环画笔
        setupPaint();

        // 设置文字画笔
        setupTextPaint();
    }

    /**
     * 初始化各种值
     */
    private void initValue() {
        // 画笔的粗细为总宽度的 1 / 15
        mStrokeWidth = mWidth / 15f;
    }

    /**
     * 设置圆环画笔
     */
    private void setupPaint() {
        // 创建圆环画笔
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(roundColor);
        mPaint.setStyle(Paint.Style.STROKE); // 边框风格
        mPaint.setStrokeWidth(mStrokeWidth);
    }

    /**
     * 设置文字画笔
     */
    private void setupTextPaint() {
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(textColor);
        mTextPaint.setTextSize(textSize);
    }

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

        // 第一步:绘制一个圆环
        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setColor(roundColor);

        float cx = mWidth / 2.0f;
        float cy = mHeight / 2.0f;
        float radius = mWidth / 2.0f - mStrokeWidth / 2.0f;
        canvas.drawCircle(cx, cy, radius, mPaint);

        // 第二步:绘制文字
        String text = ((int) (progress / maxProgress * 100)) + "%";
        Rect bounds = new Rect();
        mTextPaint.getTextBounds(text, 0, text.length(), bounds);
        canvas.drawText(text, mWidth / 2 - bounds.width() / 2, mHeight / 2 + bounds.height() / 2, mTextPaint);

        // 第三步:绘制动态进度圆环
        mPaint.setDither(true);
        mPaint.setStrokeJoin(Paint.Join.BEVEL);
        mPaint.setStrokeCap(Paint.Cap.ROUND); //  设置笔触为圆形

        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setColor(roundProgressColor);
        RectF oval = new RectF(0 + mStrokeWidth / 2, 0 + mStrokeWidth / 2,
                mWidth - mStrokeWidth / 2, mHeight - mStrokeWidth / 2);

        canvas.drawArc(oval, 0, progress / maxProgress * 360, false, mPaint);
    }

    /**
     * 重新开启动画
     */
    private void restartAnimate() {
        if (mLastProgress > 0) {
            // 取消动画
            cancelAnimate();
            // 重置进度
            setProgress(0f);
            // 重新开启动画
            runAnimate(mLastProgress);
        }
    }

    /**
     * 设置当前显示的进度条
     *
     * @param progress
     */
    public void setProgress(float progress) {
        this.progress = progress;

        // 使用 postInvalidate 比 postInvalidat() 好,线程安全
        postInvalidate();
    }


    /**
     * 开始执行动画
     *
     * @param targetProgress 最终到达的进度
     */
    public void runAnimate(float targetProgress) {
        // 运行之前,先取消上一次动画
        cancelAnimate();

        mLastProgress = targetProgress;

        mAnimator = ValueAnimator.ofObject(new FloatEvaluator(), 0, targetProgress);
        // 设置差值器
        mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                setProgress(value);
            }
        });

        mAnimator.setDuration((long) (targetProgress * 33));
        mAnimator.start();
    }

    /**
     * 取消动画
     */
    public void cancelAnimate() {
        if (mAnimator != null && mAnimator.isRunning()) {
            mAnimator.cancel();
        }
    }
}

//res下建values-w820dp下建attrs.xml和dimens.xml文件

//attrs下
<resources>

    <declare-styleable name="MyRoundProcess">
        <attr name="roundColor" format="color"/>
        <attr name="roundProgressColor" format="color"/>
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
    </declare-styleable>

</resources>
//dimens下
<resources>
    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
         (such as screen margins) for screens with more than 820dp of available width. This
         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
    <dimen name="activity_horizontal_margin">64dp</dimen>
</resources>
   

以上是关于自定义View圆环的主要内容,如果未能解决你的问题,请参考以下文章

自定义圆环输入值改变圆环宽半径颜色

自定义view圆环的改变

Android进阶——自定义View之自己绘制彩虹圆环调色板

Android自定义View和属性动画完美结合,创造出酷炫圆环动画,带标尺和进度

自定义控件:绘制圆环的实现过程

Android——自定义View