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

文章开头直接给出最终效果,一个很简单的圆形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都是从这些基础开始的,多练多敲肯定可以啃下这块硬骨头的。

猜你喜欢

转载自blog.csdn.net/m0_37194191/article/details/72805814