Android圆形进度条

自定义圆形进度条,见下图:

1、自定义进度条类:

package com.example.msh.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import com.example.msh.mshaliapp.R;

/**
 * 自定义圆形进度条
 * Author:William(徐威)
 * Create Time:2018-08-15
 */
public class PercentCircle extends View {
    //全局变量
    private Paint mTextPaint;
    private Paint mBackgroundPaint;
    private Paint mRingPaint;
    private int mCircleX;
    private int mCircleY;
    private float mCurrentAngle;
    private RectF mArcRectF;
    private float mStartSweepValue;
    private int mTargetPercent;
    private int mCurrentPercent;
    private int mDefaultRadius = 60;
    private int mRadius;
    private int mDefaultBackgroundColor = 0xffafb4db;
    private int mBackgroundColor;
    private int mDefaultRingColor = 0xff6950a1;
    private int mRingColor;
    private int mDefaultTextSize;
    private int mTextSize;
    private int mDefaultTextColor = 0xffffffff;
    private int mTextColor;
    private int progressRate = 1000;

    /**
     * 构造函数
     * Author:William(徐威)
     * Create Time:2018-08-15
     *
     * @param context
     */
    public PercentCircle(Context context) {
        super(context);
        init(context);

    }

    /**
     * 设置进度条的进度频率(微妙)
     * Author:William(徐威)
     * Create Time:2018-08-15
     *
     * @param rate (多少微妙前进1个百分比)
     */
    public void setProgressRate(int rate) {
        progressRate = rate;
    }

    public PercentCircle(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 自定义属性,attrs
        // 使用TypedArray
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PercentageRing);
        // 背景圆的半径
        mRadius = typedArray.getInt(R.styleable.PercentageRing_radius, mDefaultRadius);
        // 背景圆的颜色
        mBackgroundColor = typedArray.getColor(R.styleable.PercentageRing_circleBackground, mDefaultBackgroundColor);
        // 文字的颜色 默认白色
        mTextColor = typedArray.getColor(R.styleable.PercentageRing_textColor, mDefaultTextColor);
        // 外圆环的颜色
        mRingColor = typedArray.getColor(R.styleable.PercentageRing_ringColor, mDefaultRingColor);
        typedArray.recycle();

        init(context);
    }

    public PercentCircle(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    /**
     * 初始化
     * Author:William(徐威)
     * Create Time:2018-08-15
     * @param context
     */
    private void init(Context context) {
        //圆环开始角度 -90° 正北方向
        mStartSweepValue = -90;
        //当前角度
        mCurrentAngle = 0;
        //当前百分比
        mCurrentPercent = 0;

        //设置中心园的画笔
        mBackgroundPaint = new Paint();
        mBackgroundPaint.setAntiAlias(true);
        mBackgroundPaint.setColor(mBackgroundColor);
        mBackgroundPaint.setStyle(Paint.Style.FILL);

        //设置文字的画笔
        mTextPaint = new Paint();
        mTextPaint.setColor(mTextColor);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setStrokeWidth((int) (0.025 * mRadius));
        mTextPaint.setTextSize(mRadius / 2);   //文字大小为半径的一半
        mTextPaint.setTextAlign(Paint.Align.CENTER);

        //设置外圆环的画笔
        mRingPaint = new Paint();
        mRingPaint.setAntiAlias(true);
        mRingPaint.setColor(mRingColor);
        mRingPaint.setStyle(Paint.Style.STROKE);
        mRingPaint.setStrokeWidth((float) (0.075 * mRadius));

        //获得文字的字号 因为要设置文字在圆的中心位置
        mTextSize = (int) mTextPaint.getTextSize();
    }

    // 主要是测量wrap_content时候的宽和高,因为宽高一样,只需要测量一次宽即可,高等于宽
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measure(widthMeasureSpec), measure(widthMeasureSpec));
    }

    // 当wrap_content的时候,view的大小根据半径大小改变,但最大不会超过屏幕
    private int measure(int measureSpec) {
        int result = 0;
        /**
         * 1、先获取测量模式 和 测量大小
         * 2、如果测量模式是MatchParent 或者精确值,则宽为测量的宽
         * 3、如果测量模式是WrapContent ,则宽为 直径值 与 测量宽中的较小值;否则当直径大于测量宽时,会绘制到屏幕之外;
         */
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = (int) (mRadius * 2 + mRingPaint.getStrokeWidth() * 2);
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    /**
     * 实现View布局
     * Author:William(徐威)
     * Create Time:2018-08-15
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        /**
         * 1、如果半径大于圆心的横坐标,需要手动缩小半径的值,否则画到屏幕之外;
         * 2、改变了半径,则需要重新设置字体大小;
         * 3、改变了半径,则需要重新设置外圆环的宽度
         * 4、画背景圆的外接矩形,用来画圆环;
         */
        mCircleX = getMeasuredWidth() / 2;
        mCircleY = getMeasuredHeight() / 2;
        if (mRadius > mCircleX) {
            mRadius = mCircleX;
            mRadius = (int) (mCircleX - 0.075 * mRadius);
            mTextPaint.setStrokeWidth((float) (0.025 * mRadius));
            mTextPaint.setTextSize(mRadius / 2);
            mRingPaint.setStrokeWidth((float) (0.075 * mRadius));
            mTextSize = (int) mTextPaint.getTextSize();
        }
        mArcRectF = new RectF(mCircleX - mRadius, mCircleY - mRadius, mCircleX + mRadius, mCircleY + mRadius);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * 1、画中间背景圆
         * 2、画文字
         * 3、画圆环
         * 4、判断进度,重新绘制
         */
        canvas.drawCircle(mCircleX, mCircleY, mRadius, mBackgroundPaint);
        canvas.drawText(String.valueOf(mCurrentPercent) + "%", mCircleX, mCircleY + mTextSize / 4, mTextPaint);
        canvas.drawArc(mArcRectF, mStartSweepValue, mCurrentAngle, false, mRingPaint);

        if (mCurrentPercent < mTargetPercent) {
            //当前百分比+1
            mCurrentPercent += 1;
            //当前角度+360
            mCurrentAngle += 3.6;
            //按照设置的前进频率毫秒数重画一次(默认1000ms)
            postInvalidateDelayed(progressRate);
        }
    }

    /**
     * 设置最大百分比
     * Author:William(徐威)
     * Create Time:2018-08-15
     * @param targetPercent
     */
    public void setTargetPercent(int targetPercent) {
        mTargetPercent = targetPercent;
    }
}
2、前端UI页面Xml文件布局引入:
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="350dp"
    android:gravity="center"
    android:minHeight="25px"
    android:minWidth="25px"
    android:orientation="horizontal">

    <com.example.msh.view.PercentCircle
        android:id="@+id/pCircleBar"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        app:circleBackground="#F39800"
        app:radius="250"
        app:ringColor="#73B347"
        app:textColor="#ffffff" />
</LinearLayout>

3、Activity后台操作:

PercentCircle pCircleBar = (PercentCircle) findViewById(R.id.pCircleBar);
pCircleBar.setProgressRate(120);//设置进度条前进频率,单位微妙,此处是120微妙前进1%
pCircleBar.setTargetPercent(100);//设置进度条最大可以到达的百分比,此处设置是到达100%
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
总共分为三层:一层为圆形边线,一层为进度边线,一层用来显示标识进度节点。 public class CircleProgressBar extends View { private int maxProgress = 100; private int progress = 15; private int progressStrokeWidth = 2; private int marxArcStorkeWidth = 16; // 画圆所在的距形区域 RectF oval; Paint paint; public CircleProgressBar(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub oval = new RectF(); paint = new Paint(); } @Override protected void onDraw(Canvas canvas) { // TODO 自动生成的方法存根 super.onDraw(canvas); int width = this.getWidth(); int height = this.getHeight(); width = (width > height) ? height : width; height = (width > height) ? height : width; paint.setAntiAlias(true); // 设置画笔为抗锯齿 paint.setColor(Color.WHITE); // 设置画笔颜色 canvas.drawColor(Color.TRANSPARENT); // 白色背景 paint.setStrokeWidth(progressStrokeWidth); // 线宽 paint.setStyle(Style.STROKE); oval.left = marxArcStorkeWidth / 2; // 左上角x oval.top = marxArcStorkeWidth / 2; // 左上角y oval.right = width - marxArcStorkeWidth / 2; // 左下角x oval.bottom = height - marxArcStorkeWidth / 2; // 右下角y canvas.drawArc(oval, -90, 360, false, paint); // 绘制白色圆圈,即进度条背景 paint.setColor(Color.rgb(0x57, 0x87, 0xb6)); paint.setStrokeWidth(marxArcStorkeWidth); canvas.drawArc(oval, -90, ((float) progress / maxProgress) * 360, false, paint); // 绘制进度圆弧,这里是蓝色 paint.setStrokeWidth(1); String text = progress + "%"; int textHeight = height / 4; paint.setTextSize(textHeight); int textWidth = (int) paint.measureText(text, 0, text.length()); paint.setStyle(Style.FILL); canvas.drawText(text, width / 2 - textWidth / 2, height / 2 + textHeight / 2, paint); } public int getMaxProgress() { return maxProgress; } public void setMaxProgress(int maxProgress) { this.maxProgress = maxProgress; } /** * 设置进度 * * @param progress * 进度百分比 * @param view * 标识进度的节点视图 */ public void setProgress(int progress, View view) { this.progress = progress; view.setAnimation(pointRotationAnima(0, (int) (((float) 360 / maxProgress) * progress))); this.invalidate(); } /** * 非UI线程调用 */ public void setProgressNotInUiThread(int progress, View view) { this.progress = progress; view.setAnimation(pointRotationAnima(0, (int) (((float) 360 / maxProgress) * progress))); this.postInvalidate(); } /** * 进度标注点的动画 * * @param fromDegrees * @param toDegrees * @return */ private Animation pointRotationAnima(float fromDegrees, float toDegrees) { int initDegress = 306;// 进度点起始位置(图片偏移约54度) RotateAnimation animation = new RotateAnimation(fromDegrees, initDegress + toDegrees, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); animation.setDuration(1);// 设置动画执行时间 animation.setRepeatCount(1);// 设置重复执行次数 animation.setFillAfter(true);// 设置动画结束后是否停留在结束位置 return animation; } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值