自定义View实现圆形进度条

本例子是实现了一个圆形的进度条功能,同时还可以控制进度的速度。

先上效果图:


Android自定义View的实现步骤:

1、自定义View的属性

2、在自定义View的构造方法中获取属性

3、[ 重写onMeasure ] 方法

4、重写 onDraw方法

第三步并不是必须的 但是大部分自定义控件都是需要的。


从上图我们可以看出需要自定义的一些属性:圆环的底色,进度条颜色,进度字体大小,进度字体颜色,速度,圆环的宽度 。这就是我们需要的属性。

    <declare-styleable name="MyView01">
        <attr name="fisrtColor" format="color" />
        <attr name="secondColor" format="color" />
        <attr name="speed" format="integer" />
        <attr name="roundWidth" format="dimension" />
        <attr name="progressTextColor" format="color" />
        <attr name="progressTextSize" format="dimension" />
    </declare-styleable>


接下来就是新建一个类 继承View 并重写构造方法,在构造方法中获取自定义的属性。
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyView01, defStyleAttr, 0);
        int count = typedArray.getIndexCount();
        for (int i = 0; i < count; i++) {

            int index = typedArray.getIndex(i);
            switch (index) {
                case R.styleable.MyView01_fisrtColor:
                    mFirstColor = typedArray.getColor(index, Color.BLUE);
                    break;
                case R.styleable.MyView01_secondColor:
                    mSecondColor = typedArray.getColor(index, Color.CYAN);
                    break;
                case R.styleable.MyView01_progressTextColor:
                    mProgressTextColor = typedArray.getColor(index, Color.GREEN);
                    break;
                case R.styleable.MyView01_roundWidth:
                    mRoundWidth = typedArray.getDimensionPixelSize(index,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyView01_progressTextSize:
                    mProgressTextSize = typedArray.getDimensionPixelSize(index,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyView01_speed:
                    mSpeed = typedArray.getInt(index, 20);
                    break;
            }
        }

        typedArray.recycle();


获取了属性之后 就要在onDraw方法中进行绘制了。

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

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mRoundWidth);
        mPaint.setAntiAlias(true);
        mPaint.setColor(mFirstColor);

        //获取view的高宽
        int width = getWidth();
        int height = getHeight();
        int radius = width / 2 - mRoundWidth / 2; //半径

        canvas.drawCircle(width / 2, height / 2, radius, mPaint);//画底色

        mRectF.left = mRoundWidth / 2;
        mRectF.right = getWidth() - mRoundWidth / 2;
        mRectF.top = mRoundWidth / 2;
        mRectF.bottom = getHeight() - mRoundWidth / 2;

        mPaint.setColor(mSecondColor);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        canvas.drawArc(mRectF, -90, mProgress, false, mPaint); //画圆弧

        String drawText = mProgress * 100 / 360 + " %";
        mTextPaint.getTextBounds(drawText, 0, drawText.length(), mRect);

        canvas.drawText(drawText, getWidth() / 2 - mRect.width() / 2, getHeight() / 2 + mRect.height() / 2, mTextPaint);//进度字体

    }

为了自定义的控件宽高可以使用 ,我们还要重写onMeasure方法,默认宽高设置为200

    int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics());
    int heigth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,200, getResources().getDisplayMetrics());

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heigthMode = MeasureSpec.getMode(heightMeasureSpec);


        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {

            if (widthMode == MeasureSpec.AT_MOST) {
                width = Math.min(width, widthSize);
            }
        }


        if (heigthMode == MeasureSpec.EXACTLY) {
            heigth = heightSize;
        } else {
            if (heigthMode == MeasureSpec.AT_MOST) {
                heigth = Math.min(heigth, heightSize);
            }
        }

        setMeasuredDimension(width, heigth);

    }

这样整个控件就绘制完成了。

但是现在的控件还不是动态的,要让其动起来还需要最后一步:

        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    while (true) {
                        mProgress++;
                        if (mProgress > 360) {
                            mProgress = 1;
                        }
                        postInvalidate();
                        Thread.sleep(mSpeed);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


            }
        }).start();

这样就大功告成。

在布局文件中使用:

 <com.ppdai.viewdemo.view.MyView01
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        app:fisrtColor="@color/colorAccent"
        app:progressTextColor="@color/colorPrimaryDark"
        app:progressTextSize="16sp"
        app:roundWidth="10dp"
        app:secondColor="@color/colorPrimary"
        app:speed="50" />



ok,最后贴上全部的View代码:


public class MyView01 extends View {

    private int mFirstColor;
    private int mSecondColor;
    private int mSpeed;
    private int mRoundWidth;
    private Paint mPaint;
    private RectF mRectF;
    private int mProgress = 1;
    private TextPaint mTextPaint;
    private int mProgressTextColor;
    private Rect mRect;
    private int mProgressTextSize;

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

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

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

        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyView01, defStyleAttr, 0);
        int count = typedArray.getIndexCount();
        for (int i = 0; i < count; i++) {

            int index = typedArray.getIndex(i);
            switch (index) {
                case R.styleable.MyView01_fisrtColor:
                    mFirstColor = typedArray.getColor(index, Color.BLUE);
                    break;
                case R.styleable.MyView01_secondColor:
                    mSecondColor = typedArray.getColor(index, Color.CYAN);
                    break;
                case R.styleable.MyView01_progressTextColor:
                    mProgressTextColor = typedArray.getColor(index, Color.GREEN);
                    break;
                case R.styleable.MyView01_roundWidth:
                    mRoundWidth = typedArray.getDimensionPixelSize(index,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyView01_progressTextSize:
                    mProgressTextSize = typedArray.getDimensionPixelSize(index,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyView01_speed:
                    mSpeed = typedArray.getInt(index, 20);
                    break;
            }
        }

        typedArray.recycle();

        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    while (true) {
                        mProgress++;
                        if (mProgress > 360) {
                            mProgress = 1;
                        }
                        postInvalidate();
                        Thread.sleep(mSpeed);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


            }
        }).start();

        mPaint = new Paint();
        mRectF = new RectF();

        mTextPaint = new TextPaint();
        mTextPaint.setColor(mProgressTextColor);
        mTextPaint.setTextSize(mProgressTextSize);
        mTextPaint.setStrokeWidth(0);
        mTextPaint.setAntiAlias(true);

        mRect = new Rect();


    }

    int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics());
    int heigth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,200, getResources().getDisplayMetrics());

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heigthMode = MeasureSpec.getMode(heightMeasureSpec);


        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {

            if (widthMode == MeasureSpec.AT_MOST) {
                width = Math.min(width, widthSize);
            }
        }


        if (heigthMode == MeasureSpec.EXACTLY) {
            heigth = heightSize;
        } else {
            if (heigthMode == MeasureSpec.AT_MOST) {
                heigth = Math.min(heigth, heightSize);
            }
        }

        setMeasuredDimension(width, heigth);

    }

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

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mRoundWidth);
        mPaint.setAntiAlias(true);
        mPaint.setColor(mFirstColor);

        //获取view的高宽
        int width = getWidth();
        int height = getHeight();
        int radius = width / 2 - mRoundWidth / 2; //半径

        canvas.drawCircle(width / 2, height / 2, radius, mPaint);//画底色

        mRectF.left = mRoundWidth / 2;
        mRectF.right = getWidth() - mRoundWidth / 2;
        mRectF.top = mRoundWidth / 2;
        mRectF.bottom = getHeight() - mRoundWidth / 2;

        mPaint.setColor(mSecondColor);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        canvas.drawArc(mRectF, -90, mProgress, false, mPaint); //画圆弧

        String drawText = mProgress * 100 / 360 + " %";
        mTextPaint.getTextBounds(drawText, 0, drawText.length(), mRect);

        canvas.drawText(drawText, getWidth() / 2 - mRect.width() / 2, getHeight() / 2 + mRect.height() / 2, mTextPaint);


    }
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的圆形进度条自定义View实现: ```java public class CircleProgressBar extends View { private float mProgress = 0; // 当前进度值 private float mMax = 100; // 最大进度值 private int mCircleWidth = 10; // 圆环宽度 private int mCircleColor = Color.GRAY; // 圆环颜色 private int mProgressColor = Color.BLUE; // 进度条颜色 private Paint mPaint; public CircleProgressBar(Context context) { super(context); init(); } public CircleProgressBar(Context context, AttributeSet attrs) { super(context, attrs); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar); mCircleWidth = ta.getDimensionPixelSize(R.styleable.CircleProgressBar_circleWidth, 10); mCircleColor = ta.getColor(R.styleable.CircleProgressBar_circleColor, Color.GRAY); mProgressColor = ta.getColor(R.styleable.CircleProgressBar_progressColor, Color.BLUE); ta.recycle(); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int centerX = getWidth() / 2; int centerY = getHeight() / 2; int radius = getWidth() / 2 - mCircleWidth / 2; // 画圆环 mPaint.setColor(mCircleColor); mPaint.setStrokeWidth(mCircleWidth); mPaint.setStyle(Paint.Style.STROKE); canvas.drawCircle(centerX, centerY, radius, mPaint); // 画进度条 mPaint.setColor(mProgressColor); mPaint.setStrokeWidth(mCircleWidth); mPaint.setStyle(Paint.Style.STROKE); RectF rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius); canvas.drawArc(rectF, -90, 360 * mProgress / mMax, false, mPaint); } public void setProgress(float progress) { mProgress = progress; invalidate(); } public void setMax(float max) { mMax = max; invalidate(); } } ``` 其中,我们可以设置圆环的宽度、圆环颜色、进度条颜色等属性。在onDraw()方法中,我们先画出圆环,然后再画出进度条进度条的弧度根据当前进度值和最大进度值计算得出。 使用时,可以在布局文件中添加如下代码: ```xml <com.example.customview.CircleProgressBar android:id="@+id/circle_progress_bar" android:layout_width="wrap_content" android:layout_height="wrap_content" app:circleColor="#FFA500" app:circleWidth="20dp" app:progressColor="#00BFFF" /> ``` 然后在代码中设置进度值即可: ```java CircleProgressBar circleProgressBar = findViewById(R.id.circle_progress_bar); circleProgressBar.setMax(100); circleProgressBar.setProgress(50); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值