简单实现一个自定义view的ProgressBar

来源:互联网 发布:电子相册的软件 编辑:程序博客网 时间:2024/06/07 11:34

文章开头直接给出最终效果,一个很简单的圆形progressBar:

这里写图片描述
很简单的一个实现效果,如果是初学自定义view的小白可以跟着一起起撸一遍这个简单效果:
首先是自定义的属性的提前准备,这块应该没什么难点,在values文件夹下面创建一个attrs的xml文件,填入自己设置的自定义属性:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="CustomProgressBar">        <attr name="roundProgressColor" format="color"></attr>        <attr name="roundColor" format="color"></attr>        <attr name="roundWidth" format="dimension"></attr>        <attr name="textsize" format="dimension"></attr>        <attr name="max" format="integer"></attr>        <attr name="textColor" format="color"></attr>        <attr name="textShow" format="boolean"></attr>        <attr name="style">            <enum name="Stroke" value="0"></enum>            <enum name="Filee" value="1"></enum>        </attr>    </declare-styleable></resources>

这里设置的自定义属性有点多啊,大致的意思大家应该都能看懂,我这就不一一述说了,后面敲代码时会有注释的。
直接上自定义view的代码了:

  private int roundProgressColor;//外围进度走时变化的颜色    private int roundColor;//初始化时圆本来的颜色    private int textColor;//中间文字的颜色    private float textSize;//文字的大小    private float roundWidth;//外围的宽    private int max;//最大,这里直接设置为100    private boolean textShow;//是否显示文字    private Paint paint;    public CustomProgressBar(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        paint=new Paint();        TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar);        roundProgressColor=typeArray.getColor(R.styleable.CustomProgressBar_roundProgressColor,Color.YELLOW);        roundColor=typeArray.getColor(R.styleable.CustomProgressBar_roundColor,Color.YELLOW);        textColor=typeArray.getColor(R.styleable.CustomProgressBar_textColor,Color.YELLOW);        textSize=typeArray.getDimension(R.styleable.CustomProgressBar_textsize,21f);        roundWidth=typeArray.getDimension(R.styleable.CustomProgressBar_roundWidth,21f);        max=typeArray.getInteger(R.styleable.CustomProgressBar_max,100);        textShow=typeArray.getBoolean(R.styleable.CustomProgressBar_textShow,false);        typeArray.recycle();    }

在两个参数的构造方法中进行自定义属性的获取,记得最后将typeArray进行recycler回收。这里默认style
为Stroke的。将自定义属性获取到之后就可以在ondraw()方法中进行绘制了。当然了绘制之前为了更加的规范化,可以提前准备好各种的set和get方法。例如:

 public synchronized int getProgress(){        return progress;    }    public synchronized void setProgress(int progress){        if(progress<0){            throw new IllegalArgumentException("progress不能小于0");        }        if(progress>max){            progress = max;        }        if(progress <=max){            this.progress = progress;            postInvalidate();        }    }    public int getRoundProgressColor() {        return roundProgressColor;    }    public void setRoundProgressColor(int roundProgressColor) {        this.roundProgressColor = roundProgressColor;    }    public int getRoundColor() {        return roundColor;    }

这里着重讲一下setProgress()方法。这个方法很显然是用来重绘整个view的,外界通过setProgress()来调用postInvalidate()进行重绘,使得整个progressBar跑起来。
话不多说看核心的onDraw()内部的方法:

 @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //画默认的大圆环        int center = getWidth()/2;//中心坐标点        float radius =  center-roundWidth/2;//半径        paint.setColor(roundColor);        paint.setStyle(Paint.Style.STROKE);        paint.setStrokeWidth(roundWidth);        canvas.drawCircle(center,center,radius,paint);

这没什么好讲的,就是绘制了一个圆,将宽度的一半设置为中心点进行绘制。

  //画文字        paint.setTextSize(textSize);        paint.setTextSkewX(-0.25f);        paint.setStrokeWidth(0);        int percent=progress*100/max;        String percentStr=percent+"%";        if(textShow)        canvas.drawText(percentStr,(getWidth()-paint.measureText(percentStr))/2f,                getWidth()/2f-(paint.descent()-paint.ascent())/2f,paint);

画文字这块计算坐标如果是没有做过文本测量的可能会看不太懂,大家可以查一下这方面的东西补一下,不难,另外需要注意的是你需要将paint.setStrokeWidth(0)重新进行set,不然最终得到的中心显示百分比的会是一团乱,因为你将文字也添加了StrokeWidth。
这里我将文字的一下显示方位画下来可以给大家看一下,方便大家理解:
这里写图片描述

OK,大家可以去看一下文字的一些绘制资料来丰富自己的知识,这块在自定义中也是很重要的,我们直接看下面的:

//画圆弧        RectF rectF=new RectF(center-radius,center-radius,center+radius,center+radius);        paint.setColor(roundProgressColor);        paint.setStrokeWidth(roundWidth);        canvas.drawArc(rectF,0,360*progress/max,false,paint);

画圆弧的代码中我用的是canvas.drawArc(rectF,0,360*progress/max,false,paint)的方法来绘制圆弧。
这个方法第一个参数是一个区域的坐标限制,参数的表达意思依次为左上右下,咱们是在一个应该是正方形中进行的圆弧的绘制,所以计算很方便。
在布局文件中的布局代码如下:

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout 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"    tools:context="com.example.administrator.costompaint.MainActivity">  <com.example.administrator.costompaint.CustomProgressBar      android:layout_width="300dp"      android:layout_height="300dp"      android:id="@+id/progressbar"      app:roundColor="@color/colorAccent"      app:roundProgressColor="@color/colorPrimary"      app:textColor="#00ff00"      app:textShow="true"      app:roundWidth="10dp"      /></android.support.constraint.ConstraintLayout>

可以看到,Android Studio真的很强大,不需要咱们再去定义命名空间就可以直接使用app:来进行自定义属性的添加,赞一个。
那么最后一步呢就是让它转起来了,在MainActivity中设置一个监听,让他去不断的setProgress()不就能跑起来了吗?

 CustomProgressBar customProgressBar;    private int progress;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        customProgressBar= (CustomProgressBar) findViewById(R.id.progressbar);        customProgressBar.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(){                    @Override                    public void run() {                        while(progress<=100) {                            progress+=3;                            customProgressBar.setProgress(progress);                            try {                                Thread.sleep(500);                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        }                    }                }.start();            }        });    }

是不是很简单?其实任何的高深的自定义view都是从这些基础开始的,多练多敲肯定可以啃下这块硬骨头的。