自定义view之动态圆形进度条

很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View的颜色都不相同,这时候如果没有自定义属性,那我们是不是需要构建不同颜色的View出来呢,这样子我们的代码就会显得很沉厄,所以这时候我们就需要自定义其属性来满足我们不同的需求,自定义属性呢,我们需要在values下建立attrs.xml文件,在其中定义我们需要定义的属性,然后在自定义View中也要做相对应的修改,我们还是用一个小例子来看看自定义View和自定义属性的使用


今天带大家来自己定义一个带进度的圆形进度条,我们还是先看一下效果吧


自定义view之动态圆形进度条自定义view之动态圆形进度条


1.在values下面新建一个attrs.xml,现在里面定义我们的属性,不同的属性对应不同的format,属性对应的format可以参考http://blog.csdn.net/pgalxx/article/details/6766677,介绍的还是比较详细,接下来我贴上我在自定义这个进度条所用到的属性

  1. <?xml version="1.0" encoding="UTF-8"?>
    <resources>
        
        <!--自定义实现写字板-->
        <declare-styleable name="CustomPaint">
            <attr name="boardBackground" format="color"></attr> <!--写字板背景颜色-->
            <attr name="paintColor" format="color"></attr><!--画笔颜色-->
            <attr name="paintWidth" format="dimension"></attr><!--画笔宽度-->
        </declare-styleable>
    
        <!--自定义进度条-->
        <declare-styleable name="CustomProgress">
            <attr name="radius" format="dimension" /><!--半径-->
            <attr name="strokeWidth" format="dimension" /><!--画笔宽度-->
            <attr name="circleColor" format="color" /><!--内圆颜色-->
            <attr name="ringColor" format="color" /><!--进度条颜色-->
            <attr name="totalProgress" format="integer" /><!--总进度-->
            <attr name="textColor" format="color|reference" /><!--字体颜色-->
            <attr name="bigCircleColor" format="color" /><!--外圆颜色-->
        </declare-styleable>
    </resources>

           2.自定义paint的全部代码贴出来,里面的代码我也有详细的注释 
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * @类的用途:
 * @author: 李晓倩
 * @date: 2017/6/11
 */

public class CustomPaint extends View {

    private int mBoardBackground;//写字板背景颜色
    private int mPaintColor;//画笔颜色
    private int mPaintWidth;//画笔宽度

    private Paint mPaint;
    private Path mPath;


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

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

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


    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomPaint);
        mBoardBackground = typedArray.getColor(R.styleable.CustomPaint_boardBackground, Color.WHITE);
        mPaintColor = typedArray.getColor(R.styleable.CustomPaint_paintColor, Color.BLACK);
        mPaintWidth = typedArray.getDimensionPixelSize(R.styleable.CustomPaint_paintWidth, 15);
        typedArray.recycle();

        mPaint = new Paint();
        mPath = new Path();

        setBackgroundColor(mBoardBackground);
        mPaint.setColor(mPaintColor);
        mPaint.setStrokeWidth(mPaintWidth);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(mPath, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        float touchX = event.getX();
        float touchY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPath.moveTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_MOVE:
                mPath.lineTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        invalidate();
        return true;
    }
}

 3.自定义View的全部代码贴出来,里面的代码我也有详细的注释 
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
 * @类的用途:
 * @author: 李晓倩
 * @date: 2017/6/11
 */

public class CustomProgress extends View {
    // 画实心圆的画笔
    private Paint mCirclePaint;
    // 画圆环的画笔
    private Paint mRingPaint;
    // 画字体的画笔
    private Paint mTextPaint;
    // 圆形颜色
    private int mCircleColor;
    // 圆环颜色
    private int mRingColor;
    // 半径
    private float mRadius;
    // 圆环半径
    private float mRingRadius;
    // 圆环宽度
    private float mStrokeWidth;
    // 圆心x坐标
    private int mXCenter;
    // 圆心y坐标
    private int mYCenter;
    // 字的长度
    private float mTxtWidth;
    // 字的高度
    private float mTxtHeight;
    // 总进度
    private int mTotalProgress;
    // 当前进度
    private int mProgress;
    //大圆
    private Paint mBigPatient;
    //字体颜色
    private int mTextColor;
    //外圆颜色
    private int mBigCircleColor;

    public CustomProgress(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 获取自定义的属性
        initAttrs(context, attrs);
        initVariable();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs,
                R.styleable.CustomProgress, 0, 0);
        mRadius = typeArray.getDimension(R.styleable.CustomProgress_radius, 300);
        mStrokeWidth = typeArray.getDimension(R.styleable.CustomProgress_strokeWidth, 20);
        mCircleColor = typeArray.getColor(R.styleable.CustomProgress_circleColor, Color.BLUE);
        mRingColor = typeArray.getColor(R.styleable.CustomProgress_ringColor, Color.RED);
        mTotalProgress = typeArray.getInt(R.styleable.CustomProgress_totalProgress, 100);
        mTextColor = typeArray.getColor(R.styleable.CustomProgress_textColor, Color.WHITE);
        mBigCircleColor = typeArray.getColor(R.styleable.CustomProgress_bigCircleColor, Color.WHITE);

        typeArray.recycle();//注意这里要释放掉

        mRingRadius = mRadius + mStrokeWidth / 2;
    }

    private void initVariable() {
        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setColor(mCircleColor);
        mCirclePaint.setStrokeCap(Paint.Cap.ROUND);
        mCirclePaint.setStyle(Paint.Style.FILL);

        mRingPaint = new Paint();
        mRingPaint.setAntiAlias(true);
        mRingPaint.setColor(mRingColor);
        mRingPaint.setStrokeCap(Paint.Cap.ROUND);
        mRingPaint.setStyle(Paint.Style.STROKE);
        mRingPaint.setStrokeWidth(mStrokeWidth);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextSize(mRadius / 2);


        mBigPatient = new Paint();
        mBigPatient.setColor(mBigCircleColor);
        mBigPatient.setAntiAlias(true);
        mBigPatient.setStyle(Paint.Style.FILL);

        Paint.FontMetrics fm = mTextPaint.getFontMetrics();
        mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent);

    }

    @Override
    protected void onDraw(Canvas canvas) {

        mXCenter = getWidth() / 2;
        mYCenter = getHeight() / 2;

        canvas.drawCircle(mXCenter, mYCenter, mRadius + mStrokeWidth, mBigPatient);
        canvas.drawCircle(mXCenter, mYCenter, mRadius, mCirclePaint);

        if (mProgress > 0) {
            RectF oval = new RectF();
            oval.left = (mXCenter - mRingRadius);
            oval.top = (mYCenter - mRingRadius);
            oval.right = mRingRadius * 2 + (mXCenter - mRingRadius);
            oval.bottom = mRingRadius * 2 + (mYCenter - mRingRadius);
            canvas.drawArc(oval, -90, ((float) mProgress / mTotalProgress) * 360, false, mRingPaint); //

            String txt = (int) (mProgress * 1.0f / mTotalProgress * 100) + "%";
            mTxtWidth = mTextPaint.measureText(txt, 0, txt.length());
            canvas.drawText(txt, mXCenter - mTxtWidth / 2, mYCenter + mTxtHeight / 4, mTextPaint);
        }
    }

    public void setProgress(int progress) {
        mProgress = progress;
        postInvalidate();
    }

    public void setmTotalProgress(int totalProgress) {
        mTotalProgress = totalProgress;
    }
}
4.布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center"
              android:orientation="vertical"
              tools:context=".MainActivity"
             >

    <test.bwie.com.autoviewdemo.CustomProgress
        android:id="@+id/custom_progress"
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:bigCircleColor="#3de822"
        app:circleColor="#ffffff"
        app:radius="30dp"
        app:strokeWidth="10dp"
        app:textColor="#000" />

</LinearLayout>
 

5.使用到自定义view的activity,这里使用的MainActivity

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private CustomProgress customProgress;


    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                customProgress.setProgress(msg.arg1);
            }
            super.handleMessage(msg);
        }
    };

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

        customProgress = (CustomProgress) findViewById(R.id.custom_progress);
        customProgress.setmTotalProgress(100);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 1; i <= 100; i++) {
                        Thread.sleep(1000);
                        Message message = handler.obtainMessage();
                        message.what = 1;
                        message.arg1 = i;
                        handler.sendMessage(message);
                    }

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

    }
}