自定义view实现圆弧进度条

自定义view可以实现很多我们想要的效果,当前我使用自定义view实现了一个圆弧进度条,具体效果如下:
圆弧进度条
首先我们创建自定义控件类CircleProgressbar继承自view,在values目录下创建它的属性xml:circle_progressbar_attrs,配置相关属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="circle_progressbar">
        <attr name="BigCircleRadius" format="dimension"/>
        <attr name="NormalCircleRadius" format="dimension"/>
        <attr name="SmallCircleRadius" format="dimension"/>
        <attr name="SmallerCircleRadius" format="dimension"/>


        <attr name="BigCircleColor" format="color"/>
        <attr name="NormalCircleColor" format="color"/>
        <attr name="SmallCircleColor" format="color"/>
        <attr name="SmallerCircleColor" format="color"/>
    </declare-styleable>
</resources>

然后开始创建构造函数:

    private Paint mPaint;
    private Paint mPaint2;

    private float bigCircleRadius;
    private float normalCircleRadius;
    private float smallCircleRadius;
    private float smallerCircleRadius;

    private int bigCircleColor;
    private int normalCircleColor;
    private int smallCircleColor;
    private int smallerCircleColor;

    private int progress; //进度

    private ProgressLisener mlistener;

    private int status = 0;

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

    public CircleProgressbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        initStyledAttrs(attrs);
        initPaint();
    }

    private void initStyledAttrs(AttributeSet attrs) {
        TypedArray array = null;

        try {
            array = getContext().obtainStyledAttributes(attrs, R.styleable.circle_progressbar);
            bigCircleRadius = array.getDimension(R.styleable.circle_progressbar_BigCircleRadius, DptoPx(70));
            normalCircleRadius = array.getDimension(R.styleable.circle_progressbar_NormalCircleRadius, DptoPx(60));
            smallCircleRadius = array.getDimension(R.styleable.circle_progressbar_SmallCircleRadius, DptoPx(50));
            smallerCircleRadius = array.getDimension(R.styleable.circle_progressbar_SmallerCircleRadius, DptoPx(40));

            bigCircleColor = array.getColor(R.styleable.circle_progressbar_BigCircleColor, Color.parseColor("#033649"));
            normalCircleColor = array.getColor(R.styleable.circle_progressbar_NormalCircleColor,Color.parseColor("#036564"));
            smallCircleColor = array.getColor(R.styleable.circle_progressbar_SmallCircleColor, Color.parseColor("#CDB380"));
            smallerCircleColor = array.getColor(R.styleable.circle_progressbar_SmallerCircleColor,Color.parseColor("#E8DDCB"));

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

            bigCircleRadius = DptoPx(30);
            normalCircleRadius = DptoPx(18);
            smallCircleRadius = DptoPx(6);
            smallerCircleRadius = DptoPx(3);

            bigCircleColor = Color.parseColor("#E8DDCB");
            normalCircleColor = Color.BLUE;
            smallCircleColor = Color.RED;
            smallerCircleColor = Color.YELLOW;


        } finally {
            if (array != null) {
                array.recycle();
            }
        }
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setDither(true); //防抖动

        mPaint.setStrokeWidth(20);
        mPaint.setStyle(Paint.Style.STROKE);

        mPaint2 = new Paint();
        mPaint2.setAntiAlias(true);//抗锯齿
        mPaint2.setDither(true); //防抖动
        mPaint2.setStrokeWidth(3);
        mPaint2.setTextSize(40);
        mPaint2.setColor(Color.GREEN);

    }

写好构造函数后,重写onMeasure方法,测量控件大小。

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

        int width = 1000;//设定一个最小值

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

        if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED || heightMeasureSpec == MeasureSpec.AT_MOST || heightMeasureSpec == MeasureSpec.UNSPECIFIED) {

            width = widthSize / 2;

        } else { //至少有一个为确定值,要获取其中的最小值
            if (widthMode == MeasureSpec.EXACTLY) {
                width = Math.min(widthSize, width);
            }
            if (heightMode == MeasureSpec.EXACTLY) {
                width = Math.min(heightSize, width);
            }
        }

        setMeasuredDimension(width, width);

    }

重写onDraw方法之前,创建接口ProgressLisener,监听进度加载情况,用于接口回调:

 protected interface ProgressLisener {
        void OnPregressEnd();
    }

    public void setOnProgressListener(ProgressLisener progressListener) {
        this.mlistener = progressListener;
    }

    //获得当前进度百分比
    private String getPersentProgress(int progress) {
        double x = progress*1.0/360;

        int y = (int)(x*100);

        return y+"%";
    }

创建公有方法setProgress,方便外面更新进度:

 public void setProgress(int progress) {
        this.progress = progress;
    }

最后重写关键的onDraw方法,根据进度绘制ui:

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

        canvas.save();
        RectF rectFBig = new RectF(getWidth() / 2 - bigCircleRadius, getHeight() / 2 - bigCircleRadius, getWidth() / 2 + bigCircleRadius, getHeight() / 2 + bigCircleRadius);
        mPaint.setColor(bigCircleColor);
        //绘制大圆弧
        canvas.drawArc(rectFBig, 0, progress, false, mPaint);
        canvas.restore();

        canvas.save();
        RectF rectFNormal = new RectF(getWidth() / 2 - normalCircleRadius, getHeight() / 2 - normalCircleRadius, getWidth() / 2 + normalCircleRadius, getHeight() / 2 + normalCircleRadius);

        mPaint.setColor(normalCircleColor);
        //绘制中圆弧
        canvas.drawArc(rectFNormal, 180, progress, false, mPaint);
        canvas.restore();

        canvas.save();
        RectF rectFSmall = new RectF(getWidth() / 2 - smallCircleRadius, getHeight() / 2 - smallCircleRadius, getWidth() / 2 + smallCircleRadius, getHeight() / 2 + smallCircleRadius);
        mPaint.setColor(smallCircleColor);
        //绘制小圆弧
        canvas.drawArc(rectFSmall,90, progress, false, mPaint);
        canvas.restore();

        canvas.save();
        RectF rectFSmaller = new RectF(getWidth() / 2 - smallerCircleRadius, getHeight() / 2 - smallerCircleRadius, getWidth() / 2 + smallerCircleRadius, getHeight() / 2 + smallerCircleRadius);
        mPaint.setColor(smallerCircleColor);
        //绘制最小圆弧
        canvas.drawArc(rectFSmaller,270, progress, false, mPaint);
        canvas.restore();

        //绘制中间进度显示
        if(status == 0) {
            canvas.drawText(getPersentProgress(progress),getWidth()/2-24,getHeight()/2+16,mPaint2);
        }else {
            canvas.drawText("OK", getWidth() / 2 - 24, getHeight() / 2 + 16, mPaint2);
        }


        postInvalidate();

        //进度在360时,加载完成
        if(progress==360){
            progress = 361;
            status = 1;
            mlistener.OnPregressEnd();

        }

    }

好了,自定义view就写好了,实现得非常简单,下面我们来看一下在activity中是怎么使用的。
首先是xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.benhuan.mycircleprocessbardemo.CircleProgressbar
        android:id="@+id/cp_cpbar"
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
    <Button
        android:id="@+id/bt_load"
        android:text="load"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

在activity中,使用一个线程来模拟下载的情况,在下载完成后,终止线程,打印吐司,具体代码如下:

package com.benhuan.mycircleprocessbardemo;

import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private CircleProgressbar cpbar;

    private Button btstart;

    private int progress;

    private MyThread myThread;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        cpbar = (CircleProgressbar) findViewById(R.id.cp_cpbar);

        cpbar.setOnProgressListener(new CircleProgressbar.ProgressLisener() {

            @Override
            public void OnPregressEnd() {
                myThread.interrupted();

                Toast.makeText(MainActivity.this,"加载完毕",Toast.LENGTH_SHORT).show();
            }
        });


        myThread = new MyThread();
        btstart = (Button) findViewById(R.id.bt_load);

        btstart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!myThread.isAlive()) {
                    myThread.start();
                }
            }
        });

    }


    class MyThread extends Thread {
        @Override
        public void run() {
            super.run();
            while(!this.isInterrupted()) {
                if(progress<=360)
                cpbar.setProgress(progress++);
                SystemClock.sleep(10);
            }
        }
    }

}

全部代码就是这样了,我们看到代码不多,使用起来也十分方便,我们还可以ui和监听情况进行扩展,这里就不一一展开了。感谢您的阅读,有什么不足之处欢迎指正。
源码点此下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值