天天看點

随記11——我的簡單的自定義View之圓形進度條和長形進度條

随記11——我的簡單的自定義View之圓形進度條和長形進度條

女神鎮樓

一共兩個進度條,一個是水準的進度條,一個是圓形的進度條,效果如下:

随記11——我的簡單的自定義View之圓形進度條和長形進度條

先說圓形進度條,繼承TextView,有幾個自定義屬性:

<!--圓形進度條-->
    <declare-styleable name="circleProgressView">
        <attr name="strokeBgColor" format="color"/>
        <attr name="strokeColor" format="color"/>
        <attr name="strokeWidth" format="dimension"/>
        <attr name="progress" format="integer"/>
        <attr name="fromAngle" format="integer"/>
        <attr name="isCapRound" format="boolean"/>
    </declare-styleable>
           

strokeBgColor圓環的背景顔色(預設ff0000),strokeColor圓環顔色(預設f6f6f6),strokeWidth圓環寬度(預設10px),progress進度(預設0),fromAngle起始角度(預設0,定義從正上方為0度),isCapRound圓環進度起末是否為圓形(預設為true)。用法如下:

<com.bjl.mypractice.view.CircleProgressView
        android:id="@+id/circleProgressView"
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:strokeBgColor="@color/colorPrimary"
        app:strokeColor="@color/color_ff0000"
        app:strokeWidth="5dp"
        app:progress="20"
        app:fromAngle="0"
        android:textColor="@color/color_ff0000"
        android:textSize="16sp"
        android:text="張三"
        android:gravity="center"/>
           

View代碼如下:

/**
 * Created by Administrator on 2017/12/18.
 * 圓形進度條
 */

public class CircleProgressView extends android.support.v7.widget.AppCompatTextView {

    /**
     * 圓環預設寬度
     */
    private float defaultStrokeWidth = 10;
    /**
     * 進度值0~100
     */
    private int mProgress;
    /**
     * 起始角度0~360
     * -90為正上方
     * 0為3點位置
     */
    private int fromAngle = 0;//
//    private int textSize = 14;
//    private int textColor;//預設666666;
//    private String text = "張三";
    private boolean isCapRound = true;//進度是開頭和結尾否是圓形的
    private Paint mPaint;
    private Paint mBgPaint;
    private Paint mTextPaint;
    RectF ovl;//圓環内環繪制的區域
    private boolean isProgressing = false;//是否正在繪制進度 防止線程多重繪制

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

    public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(attrs);
    }

    private void init(AttributeSet attrs) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);


        mBgPaint = new Paint();
        mBgPaint.setAntiAlias(true);
        mBgPaint.setDither(true);
        mBgPaint.setStyle(Paint.Style.STROKE);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setDither(true);
        mTextPaint.setStyle(Paint.Style.FILL);

        int strokeColor = Color.parseColor("#ff0000");
        int strokeBgColor = Color.parseColor("#f6f6f6");
        if (attrs != null){
            TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.circleProgressView);
            strokeBgColor = array.getColor(R.styleable.circleProgressView_strokeBgColor, Color.parseColor("#f6f6f6"));
            strokeColor = array.getColor(R.styleable.circleProgressView_strokeColor, Color.parseColor("#ff0000"));
            defaultStrokeWidth = (int) array.getDimension(R.styleable.circleProgressView_strokeWidth, 10);
            mProgress = array.getInteger(R.styleable.circleProgressView_progress, 0);
            fromAngle = array.getInteger(R.styleable.circleProgressView_fromAngle, 0);
            isCapRound = array.getBoolean(R.styleable.circleProgressView_isCapRound, true);
            if (fromAngle < 0){
                fromAngle = 0;
            }else if (fromAngle > 360){
                fromAngle = -90 + fromAngle%360;
            }
            array.recycle();
        }
        if (isCapRound){
            mPaint.setStrokeCap(Paint.Cap.ROUND);
        }
        mPaint.setStrokeWidth(defaultStrokeWidth);
        mPaint.setColor(strokeColor);

        mBgPaint.setStrokeWidth(defaultStrokeWidth);
        mBgPaint.setColor(strokeBgColor);


    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);



        setMeasuredDimension(getDefaultSize(width, widthMeasureSpec), getDefaultSize(height, heightMeasureSpec));

        ovl = new RectF(0 + defaultStrokeWidth/2, 0  + defaultStrokeWidth/2, getMeasuredWidth() -  + defaultStrokeWidth/2, getMeasuredHeight() -  + defaultStrokeWidth/2);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        ovl = new RectF(0 + defaultStrokeWidth/2, 0  + defaultStrokeWidth/2, getMeasuredWidth() -  + defaultStrokeWidth/2, getMeasuredHeight() -  + defaultStrokeWidth/2);
        canvas.drawArc(ovl, fromAngle - 90, 360, false, mBgPaint);
        canvas.drawArc(ovl, fromAngle - 90, 360 * mProgress/100, false, mPaint);
//        canvas.drawText(text, getWidth()/2, getHeight()/2, mTextPaint);

    }


    public void setProgress(int progress){
        if (progress <= 0){
            progress = 0;
            mProgress  = 0;
            postInvalidate();
        }else if (progress > 100){
            progress = 100;
        }

        //解決多個線程同時修改界面的問題
        if (isProgressing)
            isProgressing = false;
        final int finalProgress = progress;
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                isProgressing = true;
                new Thread() {
                    @Override
                    public void run() {
                        super.run();
                        //防止上一個線程的影響
                        for (int i = 0; i < finalProgress; i++) {
                            mProgress = i;
                            postInvalidate();
                            try {
                                Thread.sleep(30);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            if (!isProgressing) {
                                break;
                            }
                        }
                        isProgressing = false;
                    }
                }.start();
            }
        }, 50);

    }

}
           

下面是長形進度條,同圓形進度條差不多。

自定義屬性如下:

<!--長形進度條-->
    <declare-styleable name="horProgressView">
        
        <attr name="progressColor" format="color"/>
        <attr name="progressBgColor" format="color"/>
        <attr name="progress"/>
        <attr name="isCapRound"/>

    </declare-styleable>
           

progressColor進度顔色(預設ff0000),progressBgColor進度背景顔色(預設f6f6f6),progress進度(預設0),isCapRound圓角(預設true)

用法同CricleProgressView。代碼如下:

/**
 * Created by Administrator on 2017/12/19.
 * 水準進度條
 */

public class HorProgressView extends View {

    private int strokeWidth;//進度條的高度
    private Paint mProgressPaint;
    private Paint mBgPaint;
    private int mProgress;//進度
    private int progressColor;//進度顔色 預設ff0000
    private int progressBgColor;//進度背景顔色 預設f6f6f6
    private boolean isCapRound = true;//進度是開頭和結尾否是圓形的
    private boolean isProgressing = false;//是否正在繪制進度 防止線程多重繪制

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

    public HorProgressView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HorProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet attrs){
        mProgressPaint = new Paint();
        mProgressPaint.setAntiAlias(true);
        mProgressPaint.setDither(false);
//        mProgressPaint.setStyle(Paint.Style.STROKE);
//        mProgressPaint.setStrokeCap(Paint.Cap.ROUND);

//        mBgPaint = new Paint();
//        mBgPaint.setAntiAlias(true);
//        mBgPaint.setDither(false);
        mBgPaint.setStyle(Paint.Style.STROKE);
//        mBgPaint.setStrokeCap(Paint.Cap.ROUND);


        mBgPaint = new Paint();
        mBgPaint.setAntiAlias(true);
        mBgPaint.setDither(false);
//        mBgPaint.setStyle(Paint.Style.FILL);
//        mBgPaint.setStrokeCap(Paint.Cap.ROUND);

        if (attrs != null){
            TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.horProgressView);
            progressColor = array.getColor(R.styleable.horProgressView_progressColor, Color.parseColor("#ff0000"));
            progressBgColor = array.getColor(R.styleable.horProgressView_progressBgColor, Color.parseColor("#f6f6f6"));
            mProgress = array.getInteger(R.styleable.horProgressView_progress, 0);
            isCapRound = array.getBoolean(R.styleable.horProgressView_isCapRound, true);
            if (mProgress < 0){
                mProgress = 0;
            }else if (mProgress > 100){
                mProgress = 100;
            }
            array.recycle();
        }
        if (isCapRound){
            mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
            mBgPaint.setStrokeCap(Paint.Cap.ROUND);
        }
        mProgressPaint.setColor(progressColor);
        mBgPaint.setColor(progressBgColor);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
//        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//        if (heightMode == MeasureSpec.EXACTLY)
        setMeasuredDimension(getDefaultSize(width, widthMeasureSpec), getDefaultSize(height, heightMeasureSpec));

        strokeWidth = getMeasuredHeight();
        mProgressPaint.setStrokeWidth(getMeasuredHeight());
        mBgPaint.setStrokeWidth(getMeasuredHeight());
    }

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

        if (isCapRound){
            //有圓角
            canvas.drawLine(getHeight()/2, getHeight()/2, getWidth() - getHeight()/2, getHeight()/2, mBgPaint);
//        canvas.drawRect(0, 0, getWidth(), getHeight(),mBgPaint);
            canvas.drawLine(getHeight()/2, getHeight()/2, (getWidth() - getHeight()) * mProgress / 100 + getHeight()/2, getHeight()/2, mProgressPaint);
        }else {
            canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, mBgPaint);
            canvas.drawLine(0, getHeight()/2, getWidth() * mProgress / 100 , getHeight()/2, mProgressPaint);
        }


    }

    public void setProgress(int progress) {
        if (progress <= 0){
            progress = 0;
            mProgress  = 0;
            postInvalidate();
        }else if (progress > 100){
            progress = 100;
        }

        //解決多個線程同時修改界面的問題
        if (isProgressing)
            isProgressing = false;
        final int finalProgress = progress;
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                isProgressing = true;
                new Thread() {
                    @Override
                    public void run() {
                        super.run();
                        //防止上一個線程的影響
                        for (int i = 0; i < finalProgress; i++) {
                            mProgress = i;
                            postInvalidate();
                            try {
                                Thread.sleep(30);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            if (!isProgressing) {
                                break;
                            }
                        }
                        isProgressing = false;
                    }
                }.start();
            }
        }, 50);
    }
}
           

下一篇是自定義SeekBar,還有一個我個人比較滿意的ColorLoadingView。

本期代碼下載下傳位址:回來跟下面的SeekBar及ColorLoadingView一起發吧。

Demo下載下傳連結

繼續閱讀