26
2017
09

渐变圆环进度条实现

      阅读本文章也不需要太多的自定义View基础,懂一点即可,这里的实现方式主要是逻辑,逻辑明白了,效果就很好做了。
上个效果图,给大家看一下:
这里写图片描述
是不是挺好看的,好的,下面开始实现。
说到环形进度条,我们必不可少的要用到的一个方法就是drawArc,这个是绘制弧度的必须方法,然后绘制谁都会,重要的是为什么会渐变呢?我们观察:

drawArc(Rect, Startangle, Sweepangle, false, Progresspaint)

      总共五个参数,第一个是方块模型,我们的弧形绘制都在此基础上,然后是Startangle,表示弧形开始绘制的起始角度,android里面是已顺时针为正数的,X正半轴为0,Sweepangle表示我们弧形画出的角度大小,第四个参数表示我们绘制弧度的时候要不要弧形两端和圆心连接起来,第五个参数就是我们的画笔了,好了,基本的使用方法大家已经了解了,那么可以开始了我们的思路。
      要使有渐变效果,然后又是弧形,正好弧形绘制方法里面有个画笔,那么我们只要不停的控制画笔的颜色不就可以了,说做就做,怎么做到这一点呢。
那开始绘制我们想要的效果之前,我们一定会给我们的弧形设两个基本值,那就是弧形起点的颜色,和结尾的颜色,所以中间的哪些颜色都是根据这两个颜色进行计算得来的,好了,拿到这两个值,我们可以开始计算每个位置的颜色,我们设计出一个获取颜色的方法

public int getGradient(float currentprogress, int startColor, int endColor)

我们这里有三个参数,第一个就是我们弧形绘制的进度,第二个和第三个是弧形的起始和结尾颜色,那么我们可以随时控制位置来获取颜色,具体获取方式如下:

        if (currentprogress > 1)
            currentprogress = 1;  //当前的进度值,最高不会超过1,这个值取自当前划过的角度和除以总的角度
        int alphaStart = Color.alpha(startColor);
        int redStart = Color.red(startColor);
        int blueStart = Color.blue(startColor);
        int greenStart = Color.green(startColor);
        int alphaEnd = Color.alpha(endColor);
        int redEnd = Color.red(endColor);
        int blueEnd = Color.blue(endColor);
        int greenEnd = Color.green(endColor);
        int alphaDifference = alphaEnd - alphaStart;
        int redDifference = redEnd - redStart;
        int blueDifference = blueEnd - blueStart;
        int greenDifference = greenEnd - greenStart;
        int alphaCurrent = (int) (alphaStart + currentprogress * alphaDifference);
        int redCurrent = (int) (redStart + currentprogress * redDifference);
        int blueCurrent = (int) (blueStart + currentprogress * blueDifference);
        int greenCurrent = (int) (greenStart + currentprogress * greenDifference);
        return Color.argb(alphaCurrent, redCurrent, greenCurrent, blueCurrent);  //返回当前弧度该显示的颜色

      我们可以发现进度最大是1,也就是弧形绘制完毕,其他都是正处于绘制中,这里我们分别把起始和结尾颜色给拆开了,拆成了四个参数,分别是透明度和三原色,然后计算二者的差值,最后乘以进度再加上初始颜色,即可获取我们想要的颜色。
获取颜色的问题解决了,那怎么获取绘制进度呢。
从上面我们就可以知道,照我们这样绘制的话,我们绘制出来的弧形一定是一段一段连接起来的,所以我们会用到循环,下面给出代码:

        for (int i = 0, end = (int) (currentprogress * drawAngle); i < end; i++){
        progresspaint.setColor(getGradient(i / (float)end, startColor, endColor));
        canvas.drawArc(rectf, startangle + i, 1, false, progresspaint);

注释上面几个参数:

    private float drawAngle;          //我们计算得来的值
    private int currentprogress = 0;   //当前的进度
    private int allprogress = 100;     //总的进度

      这里只有两个变量,一个i,一个是currentprogress ,据此我们可以根据进度进行绘制,而且每次绘制都是一小段。那么怎么才能不断增长我们的进度呢?
我们可以在onDraw里面做处理,具体如下:

       drawArc(canvas); //开始绘制弧度
        if (currentprogress < allprogress) {   //如果绘制进度没有完成,那么这里每次都会判断一次,接着绘制
            currentprogress++;//进度增加
            postInvalidate();//重新进行下一次的绘制
        }

      只要发现当前进度没有完成,就会接着绘制,然后传递的currentprogress 就会一次次的发现变化,也就产生的所谓的动画效果,当然我们这个控件是需要自定义属性的,同学们可以自行设置需要动态设置的属性,我总共设置了以下自定义属性:

    private int startColor;          //起始颜色
    private int endColor;            //结束颜色
    private float sweepangle;          //划过角度
    private int startangle;          //起始角度
    private int currentprogress = 0;   //当前的进度
    private int allprogress = 100;        //总的进度
    private RectF rectf;              //绘制圆环所依赖的方块
    private float progresswidth;      //圆环宽度
    private Paint progresspaint;    //圆环的画笔

      自定义属性的获取和设置默认在代码里面。
      好了,总的难点就是这样,下面给出全部代码,方便粘贴,如果不能使用,最下面还有Demo。

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

/** * Created by 23811 on 2017/09/25. */

public class ProgressColor extends View {

    private int startColor;          //起始颜色
    private int endColor;            //结束颜色
    private float sweepangle;          //划过角度
    private int startangle;          //起始角度
    private int currentprogress = 0;   //当前的进度
    private int allprogress = 100;        //总的进度
    private RectF rectf;              //绘制圆环所依赖的方块
    private float progresswidth;      //圆环宽度
    private Paint progresspaint;    //圆环的画笔
    private float drawAngle;


    //@Nullable这个注解的意思时,自定义的属性可以为空,这样的话,我们使用的时候,不去写,也不会报错
    public ProgressColor(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //获取各个自定义属性,并且初始化默认属性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ProgressColor);
        startColor = ta.getColor(R.styleable.ProgressColor_startcolor, Color.argb(255, 255, 210, 117));   //进度条初始颜色
        endColor = ta.getColor(R.styleable.ProgressColor_endcolor, Color.argb(255, 255, 57, 216));    //进度条结束颜色
        sweepangle = ta.getInt(R.styleable.ProgressColor_sweepagle, 240);    //进度条将要滑动的角度
        startangle = ta.getInt(R.styleable.ProgressColor_startangle, 150);   //进度条起始角度
        progresswidth = ta.getDimension(R.styleable.ProgressColor_progresswidth, 8f);   //进度条宽度
        ta.recycle();   //回收自定义属性资源
        progresspaint = new Paint();
        progresspaint.setAntiAlias(true);               //设置抗锯齿
        progresspaint.setStrokeWidth(progresswidth);  //设置圆环宽度
        progresspaint.setStyle(Paint.Style.STROKE);    //设置填充方式为空心
        progresspaint.setStrokeCap(Paint.Cap.ROUND);    //设置圆环弧度两边样式,取值有Cap.ROUND(圆形线冒)、Cap.SQUARE(方形线冒)、Paint.Cap.BUTT(无线冒)
        drawAngle = (float) (sweepangle / 100.0);
}

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int mMeasureWidth = getMeasuredWidth();
        int mMeasureHeight = getMeasuredHeight();
        //根据控件的大小建造绘制弧度的方块模型
        rectf = new RectF(getPaddingLeft() + progresswidth, getPaddingTop() + progresswidth,
                mMeasureWidth + getPaddingRight() - progresswidth,
                mMeasureHeight + getPaddingBottom() - progresswidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawArc(canvas); //开始绘制弧度
        if (currentprogress < allprogress) {   //如果绘制进度没有完成,那么这里每次都会判断一次,接着绘制
            currentprogress++;//进度增加
            postInvalidate();//重新进行下一次的绘制
        }
    }

    //绘制进度条
    private void drawArc(Canvas canvas) {
        //当currentprogress == 100时,也就是1 * drawAngle,完成全部绘制,从进度我们可以知道会这样一直绘制100次,每次绘制增加一点度数
        for (int i = 0, end = (int) (currentprogress * drawAngle); i < end; i++){
        //动态设置画笔的颜色,从而达到渐变的效果
        //下面有个地方需要注意,那就是i / (float)end ,这个部分的float时不可以少的,因为本身end就是一个很小的带分数的个位数,再被取整的话,就
        // 会看不见颜色的渐变了
        progresspaint.setColor(getGradient(i / (float)end, startColor, endColor));
        //下面五个参数分别是:绘制弧度需要的方形模型,绘制的起始角度,每次绘制的角度大小,绘制时是否将圆形和弧度两边连起来,以及绘制所需要的paint
        canvas.drawArc(rectf, startangle + i, 1, false, progresspaint);
        }
    }

    //这个方法的作用在于从起始和结束颜色中取三原色和透明度,然后计算得出当前划过角度的位置应该显示什么颜色
    public int getGradient(float currentprogress, int startColor, int endColor) {
        if (currentprogress > 1)
            currentprogress = 1;  //当前的进度值,最高不会超过1,这个值取自当前划过的角度和除以总的角度
        int alphaStart = Color.alpha(startColor);
        int redStart = Color.red(startColor);
        int blueStart = Color.blue(startColor);
        int greenStart = Color.green(startColor);
        int alphaEnd = Color.alpha(endColor);
        int redEnd = Color.red(endColor);
        int blueEnd = Color.blue(endColor);
        int greenEnd = Color.green(endColor);
        int alphaDifference = alphaEnd - alphaStart;
        int redDifference = redEnd - redStart;
        int blueDifference = blueEnd - blueStart;
        int greenDifference = greenEnd - greenStart;
        int alphaCurrent = (int) (alphaStart + currentprogress * alphaDifference);
        int redCurrent = (int) (redStart + currentprogress * redDifference);
        int blueCurrent = (int) (blueStart + currentprogress * blueDifference);
        int greenCurrent = (int) (greenStart + currentprogress * greenDifference);
        return Color.argb(alphaCurrent, redCurrent, greenCurrent, blueCurrent);  //返回当前弧度该显示的颜色
    }

}

      我们发现进度满值是100,所以会重复绘制100次,这意味着什么?意味着我们修改这个值就能改变我们动画的速率,不信同学们自己去试试。
      其他注释也很详细,就不多说了,使用也很简单,直接设置宽高就可以使用,其他属性自定可以去看一下对照着添加,最后,Demo:

上一篇:ios开发中计算字符串的高度 下一篇:Android Keystore System