随记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下载链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值