自定义view进度条

 <declare-styleable name="ProgressView">
        <!--circleColor 设置圆形边框的颜色 sweepColor设置扇形变换的颜色
        startAngle 设置起始角度 sweepStep 设置变换的步长-->
        <attr name="circleColor" format="color|reference"></attr>
        <attr name="sweepColor" format="color|reference"></attr>
        <attr name="startAngle" format="integer"></attr>
        <attr name="sweepStep" format="integer"></attr>
        <attr name="padding" format="integer"></attr>
    </declare-styleable>

public class ProgressView extends View {
    private int sweepStep = 10;//扇形变换的步长(就是角度)
    private int padding = 40;//外边框距离扇形的距离 填充
    private int circleColor = Color.GRAY;//边框的颜色
    private int sweepColor = Color.BLUE;//扇形颜色
    private int startAngle = 90;//起始角度
    //设置外边框圆的边框粗细
    private int storke = 20;
    private int sweepAngle = 0;//扫过的角度
    private static final int DEFAULT_WIDTH = 200;
    private static final int DEFAULT_HEIGHT = 200;
    private Paint mPaint;
    private Canvas canvas1;

    public ProgressView(Context context) {
        super(context);
    }

    //如果要在xml文件中使用该自定义控件,则必须重写两个参数的构造函数
//因为我们使用自定义的属性的时候,会默认传递过来一个AttributeSet集合
    public ProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);
        if (array != null) {
//获取我们在xml中设置的各个自定义属性
            sweepStep = array.getInteger(R.styleable.ProgressView_sweepStep, sweepStep);
            padding = array.getInteger(R.styleable.ProgressView_padding, padding);
            circleColor = array.getColor(R.styleable.ProgressView_circleColor, circleColor);
            sweepColor = array.getColor(R.styleable.ProgressView_sweepColor, sweepColor);
            startAngle = array.getInteger(R.styleable.ProgressView_startAngle, startAngle);
//回收TypeArray资源
            array.recycle();
        }
    }

    /**
     * 先绘制外边框 --内部扇形
     *
     * @param canvas
     */
    int one = 260;
    int two = 260;
    int three = 260;
    int fore =260;
    @Override
    protected void onDraw(Canvas canvas) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true); //设置抗锯齿
//绘制外层的圆框
        mPaint.setColor(circleColor);
        mPaint.setStrokeWidth(storke);
        mPaint.setStyle(Paint.Style.STROKE);//设置圆形为空心的圆
//这里我们得到控件的Height和Width,根据Heigh和Width来确定圆心的位置,来绘制外层圆
        canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2 - storke / 2, mPaint);
// Log.d("tag", "onDraw: "+getWidth());
        invalidate();//请求重新绘制view
//绘制内部的扇形
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setColor(sweepColor);
/*
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)
RectF oval 指定扇形的矩形容器对象 指定圆弧的外轮廓的矩形
float startAngle 表示圆弧的起始角度
float sweepAngle 表示圆弧走过扫过的角度 顺时针方向
boolean useCenter 如果设置为true 在绘制圆弧时将圆心包括在内,是指以一个固定的圆心来绘制弧形(扇形),
如果指定为false,则不规则绘制扇形
Paint paint 画笔 颜色 填充
public RectF(float left, float top, float right, float bottom)
float left 矩形的左边点(左切点)的x坐标
float top 矩形上边点(上切点)的y轴坐标
float right, 矩形的右边点(右切点)的x坐标
float bottom 矩形的下边点(下切点)的y坐标
*/
//RectF中的四个参数,分别对应其内切圆的四个切点的坐标

//        RectF rectF = new RectF(padding + storke,padding + storke, getWidth() - padding - storke, getWidth() - padding - storke);
//        canvas.drawArc(rectF, startAngle, sweepAngle, true, mPaint);
//        sweepAngle += sweepStep;//根据步长更新扫过的角度
//        sweepAngle = sweepAngle > 360 ? 0 : sweepAngle;
//        invalidate();//重绘view
        RectF rectF1 = new RectF(one,two,three,fore);
        canvas.drawArc(rectF1, 360f, 360f, true, mPaint);
        one = one -2;
        two = two - 2;
        three=three+2;
        fore=fore+2;
        one = one<(padding + storke)?(padding + storke):one;
        two = two<(padding + storke)?(padding + storke):two;
        three = three>(getWidth() - padding - storke)?(getWidth() - padding - storke):three;
        fore = fore>(getWidth() - padding - storke)?(getWidth() - padding - storke):fore;
        invalidate();//重绘view

    }

    //因为我们是继承的View来自定义的View,所以onMeasure()方法要重写
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int wSize = MeasureSpec.getSize(widthMeasureSpec);
        int hSize = MeasureSpec.getSize(heightMeasureSpec);
//因为绘制的是圆,所以判断一下高度或者宽度中的一个就可以。
        switch (wMode) {
            case MeasureSpec.AT_MOST://android:layout_width="warp_content"
//获取屏幕像素
                float density = getResources().getDisplayMetrics().density;
                wSize = (int) (DEFAULT_WIDTH * density);
                hSize = (int) (DEFAULT_HEIGHT * density);
                break;
//当在xml中指定控件的宽高为match_parent或者指定数值的宽高时,回调以下代码
            case MeasureSpec.EXACTLY://android:layout_width="match_parent" android:layout_width="40dp"
                wSize = hSize = Math.min(wSize, hSize);
                break;
        }
//只要重写onMeasure()方法,一定要调用以下方法,不然会报错
        setMeasuredDimension(wSize, hSize);
    }
    public void initData(){
        postInvalidate();
         one = 260;
         two = 260;
         three = 260;
         fore =260;
    }
}
public class MainActivity extends AppCompatActivity {

    private ProgressView pv;

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

        pv = (ProgressView) findViewById(R.id.pv);
    }

    public void dy(View v) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                pv.initData();
            }
        }).start();
    }

}

猜你喜欢

转载自blog.csdn.net/peotry_favour/article/details/73065732