自定义圆形经验统计View

自定义View是我们作为一个“猿”必要掌握的招数,下面介绍下招数。

1.首先在onMeasure方法中量测量View和它的内容来确定测量的宽度和高度。

onMeasure(int widthMeasureSpec, int heightMeasureSpec)

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获取视图宽高
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);
        // 取最小值
        if (mWidth != mHeight) {
            int mMin = Math.min(mWidth, mHeight);
            mWidth = mMin;
            mHeight = mMin;
        }
        setMeasuredDimension(mWidth, mHeight);
    }
2.在onDraw方法中得到Canvas(画布)绘制图案

draw(Canvas canvas)

得到画布后先用画笔(Paint)画出对应的图案。

  @Override
  public void draw(Canvas canvas) {
      super.draw(canvas);
      drawConfig(canvas);// 初始设置
      drawCircle(canvas);// 绘制圆
      drawScaleLine(canvas);// 绘制刻度线
      drawIndicator(canvas);// 绘制光标
      drawTitleText(canvas);// 绘制标题文本
      drawContentText(canvas);// 绘制内容文本
  }
3.效果图如下:


4.源码如下:
/**
 * 作者:秦川小将
 * 描述:CircleProgressView
 */
public class CircleProgressView extends View {

    private Context mContext;
    /**
     * 视图宽高
     */
    private int mWidth, mHeight;
    /**
     * 画圆所在的距形区域
     */
    private RectF mRectF;

    /**
     * 画圆和刻度线
     */
    private Paint mPaint;

    /**
     * 画光标
     */
    private Paint mIndicatorPaint;

    /**
     * 圆线条粗细
     */
    private int mStrokeWidth = 5;

    /**
     * 进度圆线条粗细
     */
    private int mProgressLineWidth = 8;

    /**
     * 刻度线粗细
     */
    private int mScaleLineWidth = 2;

    /**
     * 进度
     */
    private float mProgress = 0;

    /**
     * 进度最大值,默认100
     */
    private float mMaxProgress = 100;

    /**
     * 线条颜色
     */
    private int mCircleLineColor;

    /**
     * 进度条颜色
     */
    private int mCircleProgressLineColor;

    /**
     * 圆弧线宽
     */
    private float mCircleBorderWidth;

    /**
     * 内边距
     */
    private float mCirclePadding;

    /**
     * 标题文本
     */
    private String mTitleText;

    /**
     * 内容文本
     */
    private String mContentText;

    /**
     * 标题文本大小
     */
    private int mTitleTextSize;

    /**
     * 内容文本大小
     */
    private int mContentTextSize;

    /**
     * 标题字体颜色
     */
    private int mTitleTextColor;

    /**
     * 内容字体颜色
     */
    private int mContentTextColor;


    public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        this.mContext = context;
        mRectF = new RectF();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        TypedArray mArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView);
        mCircleLineColor = mArray.getColor(R.styleable.CircleProgressView_circleLineColor, Color.parseColor("#D3D3D3"));
        mCircleProgressLineColor = mArray.getColor(R.styleable.CircleProgressView_circleProgressLineColor, Color.parseColor("#FFFFFF"));
        mCircleBorderWidth = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleLineBorderWidth, dip2px(10));
        mCirclePadding = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleLinePadding, dip2px(5));
        mTitleTextSize = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleTitleTextSize, dip2px(20));
        mContentTextSize = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleContentTextSize, dip2px(20));
        mTitleTextColor = mArray.getColor(R.styleable.CircleProgressView_circleTitleTextColor, Color.parseColor("#FFFFFF"));
        mContentTextColor = mArray.getColor(R.styleable.CircleProgressView_circleContentTextColor, Color.parseColor("#FFFFFF"));
        mArray.recycle();
    }

    /**
     * 设置最大值
     *
     * @param maxProgress
     */
    public void setMaxProgress(float maxProgress) {
        this.mMaxProgress = maxProgress;
    }


    /**
     * 设置进度
     *
     * @param progress 进度值
     */
    public void setProgress(float progress) {
        this.mProgress = progress;
        invalidate();
    }


    /**
     * 设置进度
     *
     * @param progress 进度值
     * @param duration 动画时长
     */
    public void setProgress(float progress, long duration) {
        setProgressAnimator(progress, duration);
    }

    /**
     * 设置进度动画
     *
     * @param progress 进度值
     * @param duration 动画持续时长
     */
    private void setProgressAnimator(float progress, long duration) {
        float mDuration = ((mMaxProgress / duration) * progress) * 1000;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, progress);
        valueAnimator.setDuration((long) mDuration);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mProgress = (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.start();
    }

    /**
     * 设置进度条线条粗细
     *
     * @param width
     */
    public void setProgressLineWidth(int width) {
        this.mProgressLineWidth = width;
    }

    /**
     * 设置刻度线线条粗细
     *
     * @param width
     */
    public void setScaleLineWidth(int width) {
        this.mScaleLineWidth = width;
    }

    /**
     * 设置底圆线条颜色
     *
     * @param color
     */
    public void setCircleLineColor(int color) {
        this.mCircleLineColor = color;
    }

    /**
     * 设置进度调线条颜色
     *
     * @param color
     */
    public void setCircleProgressLineColor(int color) {
        this.mCircleProgressLineColor = color;
    }

    /**
     * 设置刻度线外边距
     *
     * @param width
     */
    public void setCircleBorderWidth(float width) {
        this.mCircleBorderWidth = width;
    }

    /**
     * 设置刻度线内边距
     *
     * @param padding
     */
    public void setCirclePadding(float padding) {
        this.mCirclePadding = padding;
    }

    /**
     * 设置标题
     *
     * @param title
     */
    public void setTitleText(String title) {
        this.mTitleText = title;
    }

    /**
     * 设置标题字体颜色
     *
     * @param color
     */
    public void setTitleTextColor(int color) {
        this.mTitleTextColor = color;
    }

    /**
     * 标题字体大小
     *
     * @param size
     */
    public void setTitleTextSize(int size) {
        this.mTitleTextSize = size;
    }

    /**
     * 设置内容
     *
     * @param content
     */
    public void setContentText(String content) {
        this.mContentText = content;
    }

    /**
     * 设置内容字体颜色
     *
     * @param color
     */
    public void setContentTextColor(int color) {
        this.mContentTextColor = color;
    }

    /**
     * 内容字体大小
     *
     * @param size
     */
    public void setContentTextSize(int size) {
        this.mContentTextSize = size;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获取视图宽高
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);
        // 取最小值
        if (mWidth != mHeight) {
            int mMin = Math.min(mWidth, mHeight);
            mWidth = mMin;
            mHeight = mMin;
        }
        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        drawConfig(canvas);// 初始设置
        drawCircle(canvas);// 绘制圆
        drawScaleLine(canvas);// 绘制刻度线
        drawIndicator(canvas);// 绘制光标
        drawTitleText(canvas);// 绘制标题文本
        drawContentText(canvas);// 绘制内容文本
    }

    /**
     * 初始设置
     */
    private void drawConfig(Canvas canvas) {
        mPaint.setAntiAlias(true);// 是否抗锯齿
        canvas.drawColor(Color.TRANSPARENT); // 设置画布为透明
        mPaint.setStyle(Paint.Style.STROKE);
        // 位置
        mRectF.left = 20; // 左上角X
        mRectF.top = 20; // 左上角Y
        mRectF.right = getWidth() - 20; // 右下角X
        mRectF.bottom = getWidth() - 20; // 右下角Y
    }

    /**
     * 绘制圆
     *
     * @param canvas
     */
    private void drawCircle(Canvas canvas) {
        canvas.save();
        // 绘制底层圆
        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setColor(mCircleLineColor);
        canvas.drawArc(mRectF, -90, 360, false, mPaint);

        // 绘制进度圆
        mPaint.setStrokeWidth(mProgressLineWidth);
        mPaint.setColor(mCircleProgressLineColor);
        canvas.drawArc(mRectF, -90, (mProgress / mMaxProgress) * 360, false, mPaint);
        canvas.restore();
    }

    /**
     * 绘制刻度线
     *
     * @param canvas
     */
    private void drawScaleLine(Canvas canvas) {
        canvas.save();
        //半径
        float mRadius = (getMeasuredWidth() - mCirclePadding * 3) / 2 - mCirclePadding;
        //X轴中点坐标
        int mCenterX = getMeasuredWidth() / 2;
        // 设置刻度线颜色
        mPaint.setColor(mCircleLineColor);
        mPaint.setStrokeWidth(mScaleLineWidth);
        for (float i = 0; i < 360; i += 3.6) {
            double mArc = i * Math.PI / 180;
            float mStartX = (float) (mCenterX + (mRadius - mCircleBorderWidth) * Math.sin(mArc));
            float mStartY = (float) (mCenterX + (mRadius - mCircleBorderWidth) * Math.cos(mArc));
            float mStopX = (float) (mCenterX + mRadius * Math.sin(mArc) + 1);
            float mStopY = (float) (mCenterX + mRadius * Math.cos(mArc) + 1);
            canvas.drawLine(mStartX, mStartY, mStopX, mStopY, mPaint);
        }
        canvas.restore();
    }

    /**
     * 绘制光标
     *
     * @param canvas
     */
    private void drawIndicator(Canvas canvas) {
        canvas.save();
        float mRadius = getMeasuredWidth() / 2 - 20;
        // 计算从正上方旋转了多少度
        float mArc = (mProgress / mMaxProgress) * 360;
        // 计算圆弧上X,Y轴坐标
        float mIndicatorX = mRectF.centerX() + (float) (mRadius * Math.cos(Math.toRadians(mArc + 270)));
        float mIndicatorY = mRectF.centerY() + (float) (mRadius * Math.sin(Math.toRadians(mArc + 270)));
        // 设置相关属性
        mIndicatorPaint.setAntiAlias(true);
        mIndicatorPaint.setStyle(Paint.Style.FILL);
        mIndicatorPaint.setColor(mCircleProgressLineColor);
        // 设置过滤器,设置模糊效果时需关闭硬件加速器
        mIndicatorPaint.setMaskFilter(new BlurMaskFilter(dip2px(3), BlurMaskFilter.Blur.NORMAL));
        canvas.drawCircle(mIndicatorX, mIndicatorY, dip2px(3), mIndicatorPaint);
        canvas.restore();
    }

    /**
     * 绘制标题文本
     *
     * @param canvas
     */
    private void drawTitleText(Canvas canvas) {
        if (!TextUtils.isEmpty(mTitleText)) {
            canvas.save();
            mPaint.setColor(mTitleTextColor);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setTextSize(mTitleTextSize);
            int mTextHeight = mHeight / 4;
            int mTextWidth = (int) mPaint.measureText(mTitleText, 0, mTitleText.length());
            canvas.drawText(mTitleText, (mWidth / 2) - (mTextWidth / 2), (mHeight / 3) + (mTextHeight / 2), mPaint);
            canvas.restore();
        }
    }

    /**
     * 绘制内容文本
     *
     * @param canvas
     */
    private void drawContentText(Canvas canvas) {
        if (!TextUtils.isEmpty(mContentText)) {
            canvas.save();
            mPaint.setColor(mContentTextColor);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setTextSize(mContentTextSize);
            int mTextHeight = mHeight / 4;
            int mTextWidth = (int) mPaint.measureText(mContentText, 0, mContentText.length());
            canvas.drawText(mContentText, (mWidth / 2) - (mTextWidth / 2), ((mHeight / 4) + (mTextHeight / 2)) * 1.8F, mPaint);
            canvas.restore();
        }
    }

    public int dip2px(float dipValue) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
 }
3.自定义属性:
    <declare-styleable name="CircleProgressView">
        <!--圆内刻度线宽度-->
        <attr name="circleLineBorderWidth" format="reference|dimension|integer" />
        <!--圆内刻度线内边距-->
        <attr name="circleLinePadding" format="reference|dimension|integer" />
        <!--线条颜色-->
        <attr name="circleLineColor" format="reference|color" />
        <!--进度条线条颜色-->
        <attr name="circleProgressLineColor" format="reference|color" />
        <!--标题文本字体大小-->
        <attr name="circleTitleTextSize" format="reference|dimension|integer" />
        <!--内容文字大小-->
        <attr name="circleContentTextSize" format="reference|dimension|integer" />
        <!--标题文本字体颜色-->
        <attr name="circleTitleTextColor" format="reference|color" />
        <!--内容文本字体颜色-->
        <attr name="circleContentTextColor" format="reference|color" />
    </declare-styleable>
5.在布局中使用
  <!-- 这里只对文本Size进行了设置,其他属性根据自己需求进行设置-->
  <com.example.app.view.widget.CircleProgressView
      android:layout_width="200dp"
      android:layout_height="200dp"
      circle:circleContentTextSize="25sp" />
6.在java代码中使用
  mProgress.setTitleText("No.1");
  mProgress.setContentText("Super VIP");
  mProgress.setMaxProgress(100);
  mProgress.setProgress(60, 3000);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒙同學

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值