小巧实用的自定义Loading

今天一起来做一个简单实用的自定义Loading控件,效果如图所示:

image

说一下思路:

1.绘制两个圆环

2.圆环中绘制弧形,填充进度。

3.根据中间控件计算文字合适大小,绘制文字。

第一步,绘制两个圆环。

采用绘制弧形方法绘制,因为考虑到可能是其他形状的进度,比如椭圆等。如这种:

绘制弧形的方法为:

image

其中,第一个参数oval是一个矩形,它的作用是用来定位咱们要绘制的圆的具体大小和位置,其实说白了就是我们要绘制的圆(或者弧)的外切矩形。当然啦,这个矩形的形状可能是长方形也可能是正方形,如果是正方形咱们绘制出来的就是一个规范的圆的一段,如果是长方形,绘制出来的就是椭圆的一段。

第二个参数是说绘制的这个弧线开始的角度,一般是-90,代表从圆的顶点开始,如果设置为0则从三点钟方向。

第四个参数就是代表要绘制的这段弧线从开始到结束要划过的角度,如果是360,那画出来就是一个完整的圆形或者椭圆咯,注意,这个和startAngle参数没有太大的关系,startAngle只是看你弧形开始的位置而已。

第五个参数是是否需要绘制出圆心,我们这里不需要,设置成false即可。

接下来定义矩形的大小,

外层圆:rectFOut =new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight());

内层圆:rectFIn =new RectF(ringWidth, ringWidth, getMeasuredWidth() -ringWidth, getMeasuredHeight() -ringWidth);

getMeasuredWidth和getMeasuredHeight就是取出自身控件在测量完毕后的宽和高,这里我们就让圆环紧贴控件本身大小即可。ringWidth为定义的环的宽度,这里按照比例来取,例子中取的是getMeasuredWidth() /20。

第二步,绘制进度

绘制进度一样是采用绘制弧形的方法来做,只不过这里是一段一段的绘制。

和上面不同的是需要计算当前需要绘制的弧形的宽度和开始的位置,这里我将画笔的宽度直接设置成圆环的宽度,即上面的ringWidth变量的值。进度圆弧的外切矩形如何定义呢?想象一下,笔的宽度和圆环的宽度一样,那简单,我们绘制进度肯定是从圆环的中间位置绘制了。所以,定义进度圆弧矩形如下:

paint.setStrokeWidth(ringWidth);//先将画笔宽度设置为圆环的宽度。

ringRec =new RectF(ringWidth /2, ringWidth /2, getMeasuredWidth() -ringWidth /2, getMeasuredHeight() -ringWidth /2);

第三步,绘制文字

绘制文字,肯定是绘制在控件的中央了。那么如何确定文字字体大小呢?(因为要考虑到文字是否会越过圆环)

首先,咱们先固定文字只能占用的大小比例,这里我规定,文字只能占用内圆直径的3/5,

final float textMaxCanUseWidth =3 * (getMeasuredWidth() -ringWidth *2) /5;

然后,先定义一个文字的初始大小值,float textSize = (getMeasuredWidth() -ringWidth) /textSizeScale;//第一次文字大小。textSizeScale为一个文字所占内圆直径的大小,这里我取6。

接下来,就将画笔字体设置为当前值,测量要绘制的文字的宽度是否超过了规定值,如果是则不断的减1,循环判断。

paint.setTextSize(textSize);

float nowWidth =paint.measureText(text);

while (nowWidth > textMaxCanUseWidth) {

textSize--;

    paint.setTextSize(textSize);

    nowWidth =paint.measureText(text);

}

好了,整个步骤就这么多,最后暴露出进度设置的方法,然后可以将各种属性放到xml中,方便调用。完整代码如下:

public class LoadingView extends View {
    private static final String TAG = "LoadingView";

    Paint paint;
    int textColor;
    int circleColor;
    int fillColor;
    int startProgress = -90;
    private float goProgress = 0;
    float ringWidth = 0;
    int textSizeScale = 6;
    int defaultColor = 0;
    //////
    RectF ringRec, rectFOut, rectFIn;

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

    public LoadingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.e(TAG, "LoadingView: ");
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        //获取自定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);
        circleColor = array.getColor(R.styleable.LoadingView_circleColor, defaultColor);
        fillColor = array.getColor(R.styleable.LoadingView_fillColor, defaultColor);
        textColor = array.getColor(R.styleable.LoadingView_textColor, defaultColor);
        startProgress = array.getColor(R.styleable.LoadingView_startDegre, startProgress);
        paint = new Paint();
        paint.setColor(circleColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
    }

    /**
     * 设置当前进度
     * @param progress
     */
    public void setProgress(int progress) {
        goProgress = (float) (360 * progress * 0.01);
        invalidate();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(circleColor);
        paint.setStyle(Paint.Style.STROKE);
        //外圆环
        canvas.drawArc(rectFOut, -90, 360, false, paint);
        //内圆环
        canvas.drawArc(rectFIn, -90, 360, false, paint);
        //进度
        paint.setStrokeWidth(ringWidth);
        paint.setColor(fillColor);
        canvas.drawArc(ringRec, startProgress, goProgress, false, paint);
        //文字
        String text = (int) (goProgress / 3.6) + "%";
        float size = getTextSize(text);
        paint.setTextSize(size);
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        float textHeight = rect.bottom - rect.top;
        float textWidth = rect.right - rect.left;
        paint.setStrokeWidth(1);
        paint.setStyle(Paint.Style.FILL);
        float y = ringWidth + ((getMeasuredHeight() - 2 * ringWidth - textHeight) / 2) + textHeight;
        float x = ringWidth + ((getMeasuredWidth() - (2 * ringWidth) - textWidth) / 2);
        paint.setColor(textColor);
        canvas.drawText(text, x, y, paint);
    }

    /**
     * 计算出合适的文字字体大小
     *
     * @param text
     * @return
     */
    private float getTextSize(String text) {
        final float textMaxCanUseWidth = 3 * (getMeasuredWidth() - ringWidth * 2) / 5;
        float textSize = (getMeasuredWidth() - ringWidth) / textSizeScale;//第一次文字大小
        paint.setTextSize(textSize);
        float nowWidth = paint.measureText(text);
        while (nowWidth > textMaxCanUseWidth) {
            textSize--;
            paint.setTextSize(textSize);
            nowWidth = paint.measureText(text);
        }
        return textSize;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        ringWidth = getMeasuredWidth() / 20;
        rectFOut = new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight());
        rectFIn = new RectF(ringWidth, ringWidth, getMeasuredWidth() - ringWidth, getMeasuredHeight() - ringWidth);
        ringRec = new RectF(ringWidth / 2, ringWidth / 2, getMeasuredWidth() - ringWidth / 2, getMeasuredHeight() - ringWidth / 2);
    }

}


    
        
        
        
        
    




    

你可能感兴趣的:(小巧实用的自定义Loading)