Android进度条升级篇

Android进度条升级篇,第1张

概述先上效果图importandroid.animation.ValueAnimator;importandroid.content.Context;importandroid.content.res.Resources;importandroid.content.res.TypedArray;importandroid.graphics.Canvas;importandroid.graphics.Color;importandroid.graphics.Pain

先上效果图


import androID.animation.ValueAnimator;import androID.content.Context;import androID.content.res.Resources;import androID.content.res.TypedArray;import androID.graphics.Canvas;import androID.graphics.color;import androID.graphics.Paint;import androID.graphics.Point;import androID.graphics.RectF;import androID.graphics.SweepGradIEnt;import androID.graphics.Typeface;import androID.text.TextPaint;import androID.util.AttributeSet;import androID.util.Log;import androID.vIEw.VIEw;import com.littlejIE.circleprogress.utils.Constant;import com.littlejIE.circleprogress.utils.MiscUtil;/** * 圆形进度条,类似 QQ 健康中运动步数的 UI 控件 * Created by littlejIE on 2017/2/21. */public class CircleProgress extends VIEw {    private static final String TAG = CircleProgress.class.getSimplename();    private Context mContext;    //默认大小    private int mDefaultSize;    //是否开启抗锯齿    private boolean antiAlias;    //绘制提示    private TextPaint mHintPaint;    private CharSequence mHint;    private int mHintcolor;    private float mHintSize;    private float mHintOffset;    //绘制单位    private TextPaint munitPaint;    private CharSequence munit;    private int munitcolor;    private float munitSize;    private float munitOffset;    //绘制数值    private TextPaint mValuePaint;    private float mValue;    private float mMaxValue;    private float mValueOffset;    private int mPrecision;    private String mPrecisionFormat;    private int mValuecolor;    private float mValueSize;    //绘制圆弧    private Paint marcPaint;    private float marcWIDth;    private float mStartAngle, mSweepAngle;    private RectF mRectF;    //渐变的颜色是360度,如果只显示270,那么则会缺失部分颜色    private SweepGradIEnt mSweepGradIEnt;    private int[] mGradIEntcolors = {color.GREEN, color.YELLOW, color.RED};    //当前进度,[0.0f,1.0f]    private float mPercent;    //动画时间    private long mAnimTime;    //属性动画    private ValueAnimator mAnimator;    //绘制背景圆弧    private Paint mBgArcPaint;    private int mBgArccolor;    private float mBgArcWIDth;    //圆心坐标,半径    private Point mCenterPoint;    private float mRadius;    private float mTextOffsetPercentInRadius;    public CircleProgress(Context context, AttributeSet attrs) {        super(context, attrs);        init(context, attrs);    }    private voID init(Context context, AttributeSet attrs) {        mContext = context;        mDefaultSize = MiscUtil.diptopx(mContext, Constant.DEFAulT_SIZE);        mAnimator = new ValueAnimator();        mRectF = new RectF();        mCenterPoint = new Point();        initAttrs(attrs);        initPaint();        setValue(mValue);    }    private voID initAttrs(AttributeSet attrs) {        TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.CircleProgressbar);        antiAlias = typedArray.getBoolean(R.styleable.CircleProgressbar_antiAlias, Constant.ANTI_AliAS);        mHint = typedArray.getString(R.styleable.CircleProgressbar_hint);        mHintcolor = typedArray.getcolor(R.styleable.CircleProgressbar_hintcolor, color.BLACK);        mHintSize = typedArray.getDimension(R.styleable.CircleProgressbar_hintSize, Constant.DEFAulT_HINT_SIZE);        mValue = typedArray.getfloat(R.styleable.CircleProgressbar_value, Constant.DEFAulT_VALUE);        mMaxValue = typedArray.getfloat(R.styleable.CircleProgressbar_maxValue, Constant.DEFAulT_MAX_VALUE);        //内容数值精度格式        mPrecision = typedArray.getInt(R.styleable.CircleProgressbar_precision, 0);        mPrecisionFormat = MiscUtil.getPrecisionFormat(mPrecision);        mValuecolor = typedArray.getcolor(R.styleable.CircleProgressbar_valuecolor, color.BLACK);        mValueSize = typedArray.getDimension(R.styleable.CircleProgressbar_valueSize, Constant.DEFAulT_VALUE_SIZE);        munit = typedArray.getString(R.styleable.CircleProgressbar_unit);        munitcolor = typedArray.getcolor(R.styleable.CircleProgressbar_unitcolor, color.BLACK);        munitSize = typedArray.getDimension(R.styleable.CircleProgressbar_unitSize, Constant.DEFAulT_UNIT_SIZE);        marcWIDth = typedArray.getDimension(R.styleable.CircleProgressbar_arcWIDth, Constant.DEFAulT_ARC_WIDTH);        mStartAngle = typedArray.getfloat(R.styleable.CircleProgressbar_startAngle, Constant.DEFAulT_START_ANGLE);        mSweepAngle = typedArray.getfloat(R.styleable.CircleProgressbar_sweepAngle, Constant.DEFAulT_SWEEP_ANGLE);        mBgArccolor = typedArray.getcolor(R.styleable.CircleProgressbar_bgArccolor, color.WHITE);        mBgArcWIDth = typedArray.getDimension(R.styleable.CircleProgressbar_bgArcWIDth, Constant.DEFAulT_ARC_WIDTH);        mTextOffsetPercentInRadius = typedArray.getfloat(R.styleable.CircleProgressbar_textOffsetPercentInRadius, 0.33f);        //mPercent = typedArray.getfloat(R.styleable.CircleProgressbar_percent, 0);        mAnimTime = typedArray.getInt(R.styleable.CircleProgressbar_animTime, Constant.DEFAulT_ANIM_TIME);        int gradIEntArccolors = typedArray.getResourceID(R.styleable.CircleProgressbar_arccolors, 0);        if (gradIEntArccolors != 0) {            try {                int[] gradIEntcolors = getResources().getIntArray(gradIEntArccolors);                if (gradIEntcolors.length == 0) {//如果渐变色为数组为0,则尝试以单色读取色值                    int color = getResources().getcolor(gradIEntArccolors);                    mGradIEntcolors = new int[2];                    mGradIEntcolors[0] = color;                    mGradIEntcolors[1] = color;                } else if (gradIEntcolors.length == 1) {//如果渐变数组只有一种颜色,默认设为两种相同颜色                    mGradIEntcolors = new int[2];                    mGradIEntcolors[0] = gradIEntcolors[0];                    mGradIEntcolors[1] = gradIEntcolors[0];                } else {                    mGradIEntcolors = gradIEntcolors;                }            } catch (Resources.NotFoundException e) {                throw new Resources.NotFoundException("the give resource not found.");            }        }        typedArray.recycle();    }    private voID initPaint() {        mHintPaint = new TextPaint();        // 设置抗锯齿,会消耗较大资源,绘制图形速度会变慢。        mHintPaint.setAntiAlias(antiAlias);        // 设置绘制文字大小        mHintPaint.setTextSize(mHintSize);        // 设置画笔颜色        mHintPaint.setcolor(mHintcolor);        // 从中间向两边绘制,不需要再次计算文字        mHintPaint.setTextAlign(Paint.Align.CENTER);        mValuePaint = new TextPaint();        mValuePaint.setAntiAlias(antiAlias);        mValuePaint.setTextSize(mValueSize);        mValuePaint.setcolor(mValuecolor);        // 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等        mValuePaint.setTypeface(Typeface.DEFAulT_BolD);        mValuePaint.setTextAlign(Paint.Align.CENTER);        munitPaint = new TextPaint();        munitPaint.setAntiAlias(antiAlias);        munitPaint.setTextSize(munitSize);        munitPaint.setcolor(munitcolor);        munitPaint.setTextAlign(Paint.Align.CENTER);        marcPaint = new Paint();        marcPaint.setAntiAlias(antiAlias);        // 设置画笔的样式,为FILL,FILL_OR_stroke,或stroke        marcPaint.setStyle(Paint.Style.stroke);        // 设置画笔粗细        marcPaint.setstrokeWIDth(marcWIDth);        // 当画笔样式为stroke或FILL_OR_stroke时,设置笔刷的图形样式,如圆形样式        // Cap.ROUND,或方形样式 Cap.SQUARE        marcPaint.setstrokeCap(Paint.Cap.ROUND);        mBgArcPaint = new Paint();        mBgArcPaint.setAntiAlias(antiAlias);        mBgArcPaint.setcolor(mBgArccolor);        mBgArcPaint.setStyle(Paint.Style.stroke);        mBgArcPaint.setstrokeWIDth(mBgArcWIDth);        mBgArcPaint.setstrokeCap(Paint.Cap.ROUND);    }    @OverrIDe    protected voID onMeasure(int wIDthMeasureSpec, int heightmeasureSpec) {        super.onMeasure(wIDthMeasureSpec, heightmeasureSpec);        setMeasuredDimension(MiscUtil.measure(wIDthMeasureSpec, mDefaultSize),                MiscUtil.measure(heightmeasureSpec, mDefaultSize));    }    @OverrIDe    protected voID onSizeChanged(int w, int h, int olDW, int oldh) {        super.onSizeChanged(w, h, olDW, oldh);        Log.d(TAG, "onSizeChanged: w = " + w + "; h = " + h + "; olDW = " + olDW + "; oldh = " + oldh);        //求圆弧和背景圆弧的最大宽度        float maxArcWIDth = Math.max(marcWIDth, mBgArcWIDth);        //求最小值作为实际值        int minSize = Math.min(w - getpaddingleft() - getpaddingRight() - 2 * (int) maxArcWIDth,                h - getpaddingtop() - getpaddingBottom() - 2 * (int) maxArcWIDth);        //减去圆弧的宽度,否则会造成部分圆弧绘制在外围        mRadius = minSize / 2;        //获取圆的相关参数        mCenterPoint.x = w / 2;        mCenterPoint.y = h / 2;        //绘制圆弧的边界        mRectF.left = mCenterPoint.x - mRadius - maxArcWIDth / 2;        mRectF.top = mCenterPoint.y - mRadius - maxArcWIDth / 2;        mRectF.right = mCenterPoint.x + mRadius + maxArcWIDth / 2;        mRectF.bottom = mCenterPoint.y + mRadius + maxArcWIDth / 2;        //计算文字绘制时的 baseline        //由于文字的baseline、descent、ascent等属性只与textSize和typeface有关,所以此时可以直接计算        //若value、hint、unit由同一个画笔绘制或者需要动态设置文字的大小,则需要在每次更新后再次计算        mValueOffset = mCenterPoint.y + getBaselineOffsetFromY(mValuePaint);        mHintOffset = mCenterPoint.y - mRadius * mTextOffsetPercentInRadius + getBaselineOffsetFromY(mHintPaint);        munitOffset = mCenterPoint.y + mRadius * mTextOffsetPercentInRadius + getBaselineOffsetFromY(munitPaint);        updateArcPaint();        Log.d(TAG, "onSizeChanged: 控件大小 = " + "(" + w + ", " + h + ")"                + "圆心坐标 = " + mCenterPoint.toString()                + ";圆半径 = " + mRadius                + ";圆的外接矩形 = " + mRectF.toString());    }    private float getBaselineOffsetFromY(Paint paint) {        return MiscUtil.measureTextHeight(paint) / 2;    }    @OverrIDe    protected voID onDraw(Canvas canvas) {        super.onDraw(canvas);        drawText(canvas);        drawArc(canvas);    }    /**     * 绘制内容文字     *     * @param canvas     */    private voID drawText(Canvas canvas) {        // 计算文字宽度,由于Paint已设置为居中绘制,故此处不需要重新计算        // float textWIDth = mValuePaint.measureText(mValue.toString());        // float x = mCenterPoint.x - textWIDth / 2;        canvas.drawText(String.format(mPrecisionFormat, mValue), mCenterPoint.x, mValueOffset, mValuePaint);        if (mHint != null) {            canvas.drawText(mHint.toString(), mCenterPoint.x, mHintOffset, mHintPaint);        }        if (munit != null) {            canvas.drawText(munit.toString(), mCenterPoint.x, munitOffset, munitPaint);        }    }    private voID drawArc(Canvas canvas) {        // 绘制背景圆弧        // 从进度圆弧结束的地方开始重新绘制,优化性能        canvas.save();        float currentAngle = mSweepAngle * mPercent;        canvas.rotate(mStartAngle, mCenterPoint.x, mCenterPoint.y);        canvas.drawArc(mRectF, currentAngle, mSweepAngle - currentAngle + 2, false, mBgArcPaint);        // 第一个参数 oval 为 RectF 类型,即圆弧显示区域        // startAngle 和 sweepAngle  均为 float 类型,分别表示圆弧起始角度和圆弧度数        // 3点钟方向为0度,顺时针递增        // 如果 startAngle < 0 或者 > 360,则相当于 startAngle % 360        // useCenter:如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形        canvas.drawArc(mRectF, 2, currentAngle, false, marcPaint);        canvas.restore();    }    /**     * 更新圆弧画笔     */    private voID updateArcPaint() {        // 设置渐变        mSweepGradIEnt = new SweepGradIEnt(mCenterPoint.x, mCenterPoint.y, mGradIEntcolors, null);        marcPaint.setShader(mSweepGradIEnt);    }    public boolean isAntiAlias() {        return antiAlias;    }    public CharSequence getHint() {        return mHint;    }    public voID setHint(CharSequence hint) {        mHint = hint;    }    public CharSequence getUnit() {        return munit;    }    public voID setUnit(CharSequence unit) {        munit = unit;    }    public float getValue() {        return mValue;    }    /**     * 设置当前值     *     * @param value     */    public voID setValue(float value) {        if (value > mMaxValue) {            value = mMaxValue;        }        float start = mPercent;        float end = value / mMaxValue;        startAnimator(start, end, mAnimTime);    }    private voID startAnimator(float start, float end, long animTime) {        mAnimator = ValueAnimator.offloat(start, end);        mAnimator.setDuration(animTime);        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @OverrIDe            public voID onAnimationUpdate(ValueAnimator animation) {                mPercent = (float) animation.getAnimatedValue();                mValue = mPercent * mMaxValue;                if (BuildConfig.DEBUG) {                    Log.d(TAG, "onAnimationUpdate: percent = " + mPercent                            + ";currentAngle = " + (mSweepAngle * mPercent)                            + ";value = " + mValue);                }                invalIDate();            }        });        mAnimator.start();    }    /**     * 获取最大值     *     * @return     */    public float getMaxValue() {        return mMaxValue;    }    /**     * 设置最大值     *     * @param maxValue     */    public voID setMaxValue(float maxValue) {        mMaxValue = maxValue;    }    /**     * 获取精度     *     * @return     */    public int getPrecision() {        return mPrecision;    }    public voID setPrecision(int precision) {        mPrecision = precision;        mPrecisionFormat = MiscUtil.getPrecisionFormat(precision);    }    public int[] getGradIEntcolors() {        return mGradIEntcolors;    }    /**     * 设置渐变     *     * @param gradIEntcolors     */    public voID setGradIEntcolors(int[] gradIEntcolors) {        mGradIEntcolors = gradIEntcolors;        updateArcPaint();    }    public long getAnimTime() {        return mAnimTime;    }    public voID setAnimTime(long animTime) {        mAnimTime = animTime;    }    /**     * 重置     */    public voID reset() {        startAnimator(mPercent, 0.0f, 1000L);    }    @OverrIDe    protected voID onDetachedFromWindow() {        super.onDetachedFromWindow();        //释放资源    }}
import androID.animation.ValueAnimator;import androID.content.Context;import androID.content.res.Resources;import androID.content.res.TypedArray;import androID.graphics.Canvas;import androID.graphics.color;import androID.graphics.Paint;import androID.graphics.Point;import androID.graphics.RectF;import androID.graphics.SweepGradIEnt;import androID.graphics.Typeface;import androID.text.TextPaint;import androID.util.AttributeSet;import androID.util.Log;import androID.vIEw.VIEw;import com.littlejIE.circleprogress.utils.Constant;import com.littlejIE.circleprogress.utils.MiscUtil;/** * 带有刻度的圆形进度条 * Created by littlejIE on 2017/2/26. */public class DialProgress extends VIEw {    private static final String TAG = DialProgress.class.getSimplename();    private Context mContext;    //圆心坐标    private Point mCenterPoint;    private float mRadius;    private float mTextOffsetPercentInRadius;    private boolean antiAlias;    //绘制提示    private TextPaint mHintPaint;    private CharSequence mHint;    private int mHintcolor;    private float mHintSize;    private float mHintOffset;    //绘制数值    private Paint mValuePaint;    private int mValuecolor;    private float mMaxValue;    private float mValue;    private float mValueSize;    private float mValueOffset;    private String mPrecisionFormat;    //绘制单位    private Paint munitPaint;    private float munitSize;    private int munitcolor;    private float munitOffset;    private CharSequence munit;    //前景圆弧    private Paint marcPaint;    private float marcWIDth;    private int mDialintervalDegree;    private float mStartAngle, mSweepAngle;    private RectF mRectF;    //渐变    private int[] mGradIEntcolors = {color.GREEN, color.YELLOW, color.RED};    //当前进度,[0.0f,1.0f]    private float mPercent;    //动画时间    private long mAnimTime;    //属性动画    private ValueAnimator mAnimator;    //背景圆弧    private Paint mBgArcPaint;    private int mBgArccolor;    //刻度线颜色    private Paint mDialPaint;    private float mDialWIDth;    private int mDialcolor;    private int mDefaultSize;    public DialProgress(Context context, AttributeSet attrs) {        super(context, attrs);        init(context, attrs);    }    private voID init(Context context, AttributeSet attrs) {        mContext = context;        mDefaultSize = MiscUtil.diptopx(context, Constant.DEFAulT_SIZE);        mRectF = new RectF();        mCenterPoint = new Point();        initConfig(context, attrs);        initPaint();        setValue(mValue);    }    private voID initConfig(Context context, AttributeSet attrs) {        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DialProgress);        antiAlias = typedArray.getBoolean(R.styleable.DialProgress_antiAlias, true);        mMaxValue = typedArray.getfloat(R.styleable.DialProgress_maxValue, Constant.DEFAulT_MAX_VALUE);        mValue = typedArray.getfloat(R.styleable.DialProgress_value, Constant.DEFAulT_VALUE);        mValueSize = typedArray.getDimension(R.styleable.DialProgress_valueSize, Constant.DEFAulT_VALUE_SIZE);        mValuecolor = typedArray.getcolor(R.styleable.DialProgress_valuecolor, color.BLACK);        mDialintervalDegree = typedArray.getInt(R.styleable.DialProgress_dialintervalDegree, 10);        int precision = typedArray.getInt(R.styleable.DialProgress_precision, 0);        mPrecisionFormat = MiscUtil.getPrecisionFormat(precision);        munit = typedArray.getString(R.styleable.DialProgress_unit);        munitcolor = typedArray.getcolor(R.styleable.DialProgress_unitcolor, color.BLACK);        munitSize = typedArray.getDimension(R.styleable.DialProgress_unitSize, Constant.DEFAulT_UNIT_SIZE);        mHint = typedArray.getString(R.styleable.DialProgress_hint);        mHintcolor = typedArray.getcolor(R.styleable.DialProgress_hintcolor, color.BLACK);        mHintSize = typedArray.getDimension(R.styleable.DialProgress_hintSize, Constant.DEFAulT_HINT_SIZE);        marcWIDth = typedArray.getDimension(R.styleable.DialProgress_arcWIDth, Constant.DEFAulT_ARC_WIDTH);        mStartAngle = typedArray.getfloat(R.styleable.DialProgress_startAngle, Constant.DEFAulT_START_ANGLE);        mSweepAngle = typedArray.getfloat(R.styleable.DialProgress_sweepAngle, Constant.DEFAulT_SWEEP_ANGLE);        mAnimTime = typedArray.getInt(R.styleable.DialProgress_animTime, Constant.DEFAulT_ANIM_TIME);        mBgArccolor = typedArray.getcolor(R.styleable.DialProgress_bgArccolor, color.GRAY);        mDialWIDth = typedArray.getDimension(R.styleable.DialProgress_dialWIDth, 2);        mDialcolor = typedArray.getcolor(R.styleable.DialProgress_dialcolor, color.WHITE);        mTextOffsetPercentInRadius = typedArray.getfloat(R.styleable.DialProgress_textOffsetPercentInRadius, 0.33f);        int gradIEntArccolors = typedArray.getResourceID(R.styleable.DialProgress_arccolors, 0);        if (gradIEntArccolors != 0) {            try {                int[] gradIEntcolors = getResources().getIntArray(gradIEntArccolors);                if (gradIEntcolors.length == 0) {                    int color = getResources().getcolor(gradIEntArccolors);                    mGradIEntcolors = new int[2];                    mGradIEntcolors[0] = color;                    mGradIEntcolors[1] = color;                } else if (gradIEntcolors.length == 1) {                    mGradIEntcolors = new int[2];                    mGradIEntcolors[0] = gradIEntcolors[0];                    mGradIEntcolors[1] = gradIEntcolors[0];                } else {                    mGradIEntcolors = gradIEntcolors;                }            } catch (Resources.NotFoundException e) {                throw new Resources.NotFoundException("the give resource not found.");            }        }        typedArray.recycle();    }    private voID initPaint() {        mHintPaint = new TextPaint();        // 设置抗锯齿,会消耗较大资源,绘制图形速度会变慢。        mHintPaint.setAntiAlias(antiAlias);        // 设置绘制文字大小        mHintPaint.setTextSize(mHintSize);        // 设置画笔颜色        mHintPaint.setcolor(mHintcolor);        // 从中间向两边绘制,不需要再次计算文字        mHintPaint.setTextAlign(Paint.Align.CENTER);        mValuePaint = new Paint();        mValuePaint.setAntiAlias(antiAlias);        mValuePaint.setTextSize(mValueSize);        mValuePaint.setcolor(mValuecolor);        mValuePaint.setTypeface(Typeface.DEFAulT_BolD);        mValuePaint.setTextAlign(Paint.Align.CENTER);        munitPaint = new Paint();        munitPaint.setAntiAlias(antiAlias);        munitPaint.setTextSize(munitSize);        munitPaint.setcolor(munitcolor);        munitPaint.setTextAlign(Paint.Align.CENTER);        marcPaint = new Paint();        marcPaint.setAntiAlias(antiAlias);        marcPaint.setStyle(Paint.Style.stroke);        marcPaint.setstrokeWIDth(marcWIDth);        marcPaint.setstrokeCap(Paint.Cap.BUTT);        mBgArcPaint = new Paint();        mBgArcPaint.setAntiAlias(antiAlias);        mBgArcPaint.setStyle(Paint.Style.stroke);        mBgArcPaint.setstrokeWIDth(marcWIDth);        mBgArcPaint.setstrokeCap(Paint.Cap.BUTT);        mBgArcPaint.setcolor(mBgArccolor);        mDialPaint = new Paint();        mDialPaint.setAntiAlias(antiAlias);        mDialPaint.setcolor(mDialcolor);        mDialPaint.setstrokeWIDth(mDialWIDth);    }    /**     * 更新圆弧画笔     */    private voID updateArcPaint() {        // 设置渐变        // 渐变的颜色是360度,如果只显示270,那么则会缺失部分颜色        SweepGradIEnt sweepGradIEnt = new SweepGradIEnt(mCenterPoint.x, mCenterPoint.y, mGradIEntcolors, null);        marcPaint.setShader(sweepGradIEnt);    }    @OverrIDe    protected voID onMeasure(int wIDthMeasureSpec, int heightmeasureSpec) {        super.onMeasure(wIDthMeasureSpec, heightmeasureSpec);        setMeasuredDimension(MiscUtil.measure(wIDthMeasureSpec, mDefaultSize),                MiscUtil.measure(heightmeasureSpec, mDefaultSize));    }    @OverrIDe    protected voID onSizeChanged(int w, int h, int olDW, int oldh) {        super.onSizeChanged(w, h, olDW, oldh);        Log.d(TAG, "onSizeChanged: w = " + w + "; h = " + h + "; olDW = " + olDW + "; oldh = " + oldh);        int minSize = Math.min(getMeasureDWIDth() - getpaddingleft() - getpaddingRight() - 2 * (int) marcWIDth,                getMeasuredHeight() - getpaddingtop() - getpaddingBottom() - 2 * (int) marcWIDth);        mRadius = minSize / 2;        mCenterPoint.x = getMeasureDWIDth() / 2;        mCenterPoint.y = getMeasuredHeight() / 2;        //绘制圆弧的边界        mRectF.left = mCenterPoint.x - mRadius - marcWIDth / 2;        mRectF.top = mCenterPoint.y - mRadius - marcWIDth / 2;        mRectF.right = mCenterPoint.x + mRadius + marcWIDth / 2;        mRectF.bottom = mCenterPoint.y + mRadius + marcWIDth / 2;        mValueOffset = mCenterPoint.y + getBaselineOffsetFromY(mValuePaint);        mHintOffset = mCenterPoint.y - mRadius * mTextOffsetPercentInRadius + getBaselineOffsetFromY(mHintPaint);        munitOffset = mCenterPoint.y + mRadius * mTextOffsetPercentInRadius + getBaselineOffsetFromY(munitPaint);        updateArcPaint();        Log.d(TAG, "onMeasure: 控件大小 = " + "(" + getMeasureDWIDth() + ", " + getMeasuredHeight() + ")"                + ";圆心坐标 = " + mCenterPoint.toString()                + ";圆半径 = " + mRadius                + ";圆的外接矩形 = " + mRectF.toString());    }    private float getBaselineOffsetFromY(Paint paint) {        return MiscUtil.measureTextHeight(paint) / 2;    }    @OverrIDe    protected voID onDraw(Canvas canvas) {        super.onDraw(canvas);        drawArc(canvas);        drawDial(canvas);        drawText(canvas);    }    private voID drawArc(Canvas canvas) {        // 绘制背景圆弧        // 从进度圆弧结束的地方开始重新绘制,优化性能        float currentAngle = mSweepAngle * mPercent;        canvas.save();        canvas.rotate(mStartAngle, mCenterPoint.x, mCenterPoint.y);        canvas.drawArc(mRectF, currentAngle, mSweepAngle - currentAngle, false, mBgArcPaint);        // 第一个参数 oval 为 RectF 类型,即圆弧显示区域        // startAngle 和 sweepAngle  均为 float 类型,分别表示圆弧起始角度和圆弧度数        // 3点钟方向为0度,顺时针递增        // 如果 startAngle < 0 或者 > 360,则相当于 startAngle % 360        // useCenter:如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形        canvas.drawArc(mRectF, 0, currentAngle, false, marcPaint);        canvas.restore();    }    private voID drawDial(Canvas canvas) {        int total = (int) (mSweepAngle / mDialintervalDegree);        canvas.save();        canvas.rotate(mStartAngle, mCenterPoint.x, mCenterPoint.y);        for (int i = 0; i <= total; i++) {            canvas.drawline(mCenterPoint.x + mRadius, mCenterPoint.y, mCenterPoint.x + mRadius + marcWIDth, mCenterPoint.y, mDialPaint);            canvas.rotate(mDialintervalDegree, mCenterPoint.x, mCenterPoint.y);        }        canvas.restore();    }    private voID drawText(Canvas canvas) {        canvas.drawText(String.format(mPrecisionFormat, mValue), mCenterPoint.x, mValueOffset, mValuePaint);        if (munit != null) {            canvas.drawText(munit.toString(), mCenterPoint.x, munitOffset, munitPaint);        }        if (mHint != null) {            canvas.drawText(mHint.toString(), mCenterPoint.x, mHintOffset, mHintPaint);        }    }    public float getMaxValue() {        return mMaxValue;    }    public voID setMaxValue(float maxValue) {        mMaxValue = maxValue;    }    /**     * 设置当前值     *     * @param value     */    public voID setValue(float value) {        if (value > mMaxValue) {            value = mMaxValue;        }        float start = mPercent;        float end = value / mMaxValue;        startAnimator(start, end, mAnimTime);    }    private voID startAnimator(float start, float end, long animTime) {        mAnimator = ValueAnimator.offloat(start, end);        mAnimator.setDuration(animTime);        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @OverrIDe            public voID onAnimationUpdate(ValueAnimator animation) {                mPercent = (float) animation.getAnimatedValue();                mValue = mPercent * mMaxValue;                if (BuildConfig.DEBUG) {                    Log.d(TAG, "onAnimationUpdate: percent = " + mPercent                            + ";currentAngle = " + (mSweepAngle * mPercent)                            + ";value = " + mValue);                }                invalIDate();            }        });        mAnimator.start();    }    public int[] getGradIEntcolors() {        return mGradIEntcolors;    }    public voID setGradIEntcolors(int[] gradIEntcolors) {        mGradIEntcolors = gradIEntcolors;        updateArcPaint();    }    public voID reset() {        startAnimator(mPercent, 0.0f, 1000L);    }}
import androID.animation.Animator;import androID.animation.ValueAnimator;import androID.annotation.TargetAPI;import androID.content.Context;import androID.content.res.TypedArray;import androID.graphics.Canvas;import androID.graphics.color;import androID.graphics.Paint;import androID.graphics.Path;import androID.graphics.Point;import androID.graphics.RectF;import androID.os.Build;import androID.text.TextPaint;import androID.util.AttributeSet;import androID.util.Log;import androID.vIEw.VIEw;import androID.vIEw.animation.linearInterpolator;import com.littlejIE.circleprogress.utils.Constant;import com.littlejIE.circleprogress.utils.MiscUtil;/** * 水波进度条 * Created by littlejIE on 2017/2/26. */public class WaveProgress extends VIEw {    private static final String TAG = WaveProgress.class.getSimplename();    //浅色波浪方向    private static final int L2R = 0;    private static final int R2L = 1;    private int mDefaultSize;    //圆心    private Point mCenterPoint;    //半径    private float mRadius;    //圆的外接矩形    private RectF mRectF;    //深色波浪移动距离    private float mDarkWaveOffset;    //浅色波浪移动距离    private float mlightWaveOffset;    //浅色波浪方向    private boolean isR2L;    //是否锁定波浪不随进度移动    private boolean lockWave;    //是否开启抗锯齿    private boolean antiAlias;    //最大值    private float mMaxValue;    //当前值    private float mValue;    //当前进度    private float mPercent;    //绘制提示    private TextPaint mHintPaint;    private CharSequence mHint;    private int mHintcolor;    private float mHintSize;    private Paint mPercentPaint;    private float mValueSize;    private int mValuecolor;    //圆环宽度    private float mCircleWIDth;    //圆环    private Paint mCirclePaint;    //圆环颜色    private int mCirclecolor;    //背景圆环颜色    private int mBgCirclecolor;    //水波路径    private Path mWavelimitPath;    private Path mWavePath;    //水波高度    private float mWaveHeight;    //水波数量    private int mWaveNum;    //深色水波    private Paint mWavePaint;    //深色水波颜色    private int mDarkWavecolor;    //浅色水波颜色    private int mlightWavecolor;    //深色水波贝塞尔曲线上的起始点、控制点    private Point[] mDarkPoints;    //浅色水波贝塞尔曲线上的起始点、控制点    private Point[] mlightPoints;    //贝塞尔曲线点的总个数    private int mAllPointCount;    private int mHalfPointCount;    private ValueAnimator mProgressAnimator;    private long mDarkWaveAnimTime;    private ValueAnimator mDarkWaveAnimator;    private long mlightWaveAnimTime;    private ValueAnimator mlightWaveAnimator;    public WaveProgress(Context context, AttributeSet attrs) {        super(context, attrs);        init(context, attrs);    }    private voID init(Context context, AttributeSet attrs) {        mDefaultSize = MiscUtil.diptopx(context, Constant.DEFAulT_SIZE);        mRectF = new RectF();        mCenterPoint = new Point();        initAttrs(context, attrs);        initPaint();        initPath();    }    private voID initAttrs(Context context, AttributeSet attrs) {        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WaveProgress);        antiAlias = typedArray.getBoolean(R.styleable.WaveProgress_antiAlias, true);        mDarkWaveAnimTime = typedArray.getInt(R.styleable.WaveProgress_darkWaveAnimTime, Constant.DEFAulT_ANIM_TIME);        mlightWaveAnimTime = typedArray.getInt(R.styleable.WaveProgress_lightWaveAnimTime, Constant.DEFAulT_ANIM_TIME);        mMaxValue = typedArray.getfloat(R.styleable.WaveProgress_maxValue, Constant.DEFAulT_MAX_VALUE);        mValue = typedArray.getfloat(R.styleable.WaveProgress_value, Constant.DEFAulT_VALUE);        mValueSize = typedArray.getDimension(R.styleable.WaveProgress_valueSize, Constant.DEFAulT_VALUE_SIZE);        mValuecolor = typedArray.getcolor(R.styleable.WaveProgress_valuecolor, color.BLACK);        mHint = typedArray.getString(R.styleable.WaveProgress_hint);        mHintcolor = typedArray.getcolor(R.styleable.WaveProgress_hintcolor, color.BLACK);        mHintSize = typedArray.getDimension(R.styleable.WaveProgress_hintSize, Constant.DEFAulT_HINT_SIZE);        mCircleWIDth = typedArray.getDimension(R.styleable.WaveProgress_circleWIDth, Constant.DEFAulT_ARC_WIDTH);        mCirclecolor = typedArray.getcolor(R.styleable.WaveProgress_circlecolor, color.GREEN);        mBgCirclecolor = typedArray.getcolor(R.styleable.WaveProgress_bgCirclecolor, color.WHITE);        mWaveHeight = typedArray.getDimension(R.styleable.WaveProgress_waveHeight, Constant.DEFAulT_WAVE_HEIGHT);        mWaveNum = typedArray.getInt(R.styleable.WaveProgress_waveNum, 1);        mDarkWavecolor = typedArray.getcolor(R.styleable.WaveProgress_darkWavecolor,                getResources().getcolor(androID.R.color.holo_blue_dark));        mlightWavecolor = typedArray.getcolor(R.styleable.WaveProgress_lightWavecolor,                getResources().getcolor(androID.R.color.holo_green_light));        isR2L = typedArray.getInt(R.styleable.WaveProgress_lightWaveDirect, R2L) == R2L;        lockWave = typedArray.getBoolean(R.styleable.WaveProgress_lockWave, false);        typedArray.recycle();    }    private voID initPaint() {        mHintPaint = new TextPaint();        // 设置抗锯齿,会消耗较大资源,绘制图形速度会变慢。        mHintPaint.setAntiAlias(antiAlias);        // 设置绘制文字大小        mHintPaint.setTextSize(mHintSize);        // 设置画笔颜色        mHintPaint.setcolor(mHintcolor);        // 从中间向两边绘制,不需要再次计算文字        mHintPaint.setTextAlign(Paint.Align.CENTER);        mCirclePaint = new Paint();        mCirclePaint.setAntiAlias(antiAlias);        mCirclePaint.setstrokeWIDth(mCircleWIDth);        mCirclePaint.setStyle(Paint.Style.stroke);        mCirclePaint.setstrokeCap(Paint.Cap.ROUND);        mWavePaint = new Paint();        mWavePaint.setAntiAlias(antiAlias);        mWavePaint.setStyle(Paint.Style.FILL);        mPercentPaint = new Paint();        mPercentPaint.setTextAlign(Paint.Align.CENTER);        mPercentPaint.setAntiAlias(antiAlias);        mPercentPaint.setcolor(mValuecolor);        mPercentPaint.setTextSize(mValueSize);    }    private voID initPath() {        mWavelimitPath = new Path();        mWavePath = new Path();    }    @OverrIDe    protected voID onMeasure(int wIDthMeasureSpec, int heightmeasureSpec) {        super.onMeasure(wIDthMeasureSpec, heightmeasureSpec);        setMeasuredDimension(MiscUtil.measure(wIDthMeasureSpec, mDefaultSize),                MiscUtil.measure(heightmeasureSpec, mDefaultSize));    }    @OverrIDe    protected voID onSizeChanged(int w, int h, int olDW, int oldh) {        super.onSizeChanged(w, h, olDW, oldh);        Log.d(TAG, "onSizeChanged: w = " + w + "; h = " + h + "; olDW = " + olDW + "; oldh = " + oldh);        int minSize = Math.min(getMeasureDWIDth() - getpaddingleft() - getpaddingRight() - 2 * (int) mCircleWIDth,                getMeasuredHeight() - getpaddingtop() - getpaddingBottom() - 2 * (int) mCircleWIDth);        mRadius = minSize / 2;        mCenterPoint.x = getMeasureDWIDth() / 2;        mCenterPoint.y = getMeasuredHeight() / 2;        //绘制圆弧的边界        mRectF.left = mCenterPoint.x - mRadius - mCircleWIDth / 2;        mRectF.top = mCenterPoint.y - mRadius - mCircleWIDth / 2;        mRectF.right = mCenterPoint.x + mRadius + mCircleWIDth / 2;        mRectF.bottom = mCenterPoint.y + mRadius + mCircleWIDth / 2;        Log.d(TAG, "onSizeChanged: 控件大小 = " + "(" + getMeasureDWIDth() + ", " + getMeasuredHeight() + ")"                + ";圆心坐标 = " + mCenterPoint.toString()                + ";圆半径 = " + mRadius                + ";圆的外接矩形 = " + mRectF.toString());        initWavePoints();        //开始动画        setValue(mValue);        startWaveAnimator();    }    private voID initWavePoints() {        //当前波浪宽度        float waveWIDth = (mRadius * 2) / mWaveNum;        mAllPointCount = 8 * mWaveNum + 1;        mHalfPointCount = mAllPointCount / 2;        mDarkPoints = getPoint(false, waveWIDth);        mlightPoints = getPoint(isR2L, waveWIDth);    }    /**     * 从左往右或者从右往左获取贝塞尔点     *     * @return     */    private Point[] getPoint(boolean isR2L, float waveWIDth) {        Point[] points = new Point[mAllPointCount];        //第1个点特殊处理,即数组的中点        points[mHalfPointCount] = new Point((int) (mCenterPoint.x + (isR2L ? mRadius : -mRadius)), mCenterPoint.y);        //屏幕内的贝塞尔曲线点        for (int i = mHalfPointCount + 1; i < mAllPointCount; i += 4) {            float wIDth = points[mHalfPointCount].x + waveWIDth * (i / 4 - mWaveNum);            points[i] = new Point((int) (waveWIDth / 4 + wIDth), (int) (mCenterPoint.y - mWaveHeight));            points[i + 1] = new Point((int) (waveWIDth / 2 + wIDth), mCenterPoint.y);            points[i + 2] = new Point((int) (waveWIDth * 3 / 4 + wIDth), (int) (mCenterPoint.y + mWaveHeight));            points[i + 3] = new Point((int) (waveWIDth + wIDth), mCenterPoint.y);        }        //屏幕外的贝塞尔曲线点        for (int i = 0; i < mHalfPointCount; i++) {            int reverse = mAllPointCount - i - 1;            points[i] = new Point((isR2L ? 2 : 1) * points[mHalfPointCount].x - points[reverse].x,                    points[mHalfPointCount].y * 2 - points[reverse].y);        }        //对从右向左的贝塞尔点数组反序,方便后续处理        return isR2L ? MiscUtil.reverse(points) : points;    }    @OverrIDe    protected voID onDraw(Canvas canvas) {        super.onDraw(canvas);        drawCircle(canvas);        drawlightWave(canvas);        drawDarkWave(canvas);        drawProgress(canvas);    }    /**     * 绘制圆环     *     * @param canvas     */    private voID drawCircle(Canvas canvas) {        canvas.save();        canvas.rotate(270, mCenterPoint.x, mCenterPoint.y);        int currentAngle = (int) (360 * mPercent);        //画背景圆环        mCirclePaint.setcolor(mBgCirclecolor);        canvas.drawArc(mRectF, currentAngle, 360 - currentAngle, false, mCirclePaint);        //画圆环        mCirclePaint.setcolor(mCirclecolor);        canvas.drawArc(mRectF, 0, currentAngle, false, mCirclePaint);        canvas.restore();    }    /**     * 绘制深色波浪(贝塞尔曲线)     *     * @param canvas     */    private voID drawDarkWave(Canvas canvas) {        mWavePaint.setcolor(mDarkWavecolor);        drawWave(canvas, mWavePaint, mDarkPoints, mDarkWaveOffset);    }    /**     * 绘制浅色波浪(贝塞尔曲线)     *     * @param canvas     */    private voID drawlightWave(Canvas canvas) {        mWavePaint.setcolor(mlightWavecolor);        //从右向左的水波位移应该被减去        drawWave(canvas, mWavePaint, mlightPoints, isR2L ? -mlightWaveOffset : mlightWaveOffset);    }    @TargetAPI(Build.VERSION_CODES.KITKAT)    private voID drawWave(Canvas canvas, Paint paint, Point[] points, float waveOffset) {        mWavelimitPath.reset();        mWavePath.reset();        float height = lockWave ? 0 : mRadius - 2 * mRadius * mPercent;        //moveto和lineto绘制出水波区域矩形        mWavePath.moveto(points[0].x + waveOffset, points[0].y + height);        for (int i = 1; i < mAllPointCount; i += 2) {            mWavePath.quadTo(points[i].x + waveOffset, points[i].y + height,                    points[i + 1].x + waveOffset, points[i + 1].y + height);        }        //mWavePath.lineto(points[mAllPointCount - 1].x, points[mAllPointCount - 1].y + height);        //不管如何移动,波浪与圆路径的交集底部永远固定,否则会造成上移的时候底部为空的情况        mWavePath.lineto(points[mAllPointCount - 1].x, mCenterPoint.y + mRadius);        mWavePath.lineto(points[0].x, mCenterPoint.y + mRadius);        mWavePath.close();        mWavelimitPath.addCircle(mCenterPoint.x, mCenterPoint.y, mRadius, Path.Direction.CW);        //取该圆与波浪路径的交集,形成波浪在圆内的效果        mWavelimitPath.op(mWavePath, Path.Op.INTERSECT);        canvas.drawPath(mWavelimitPath, paint);    }    //前一次绘制时的进度    private float mPrePercent;    //当前进度值    private String mPercentValue;    private voID drawProgress(Canvas canvas) {        float y = mCenterPoint.y - (mPercentPaint.descent() + mPercentPaint.ascent()) / 2;        if (BuildConfig.DEBUG) {            Log.d(TAG, "mPercent = " + mPercent + "; mPrePercent = " + mPrePercent);        }        if (mPrePercent == 0.0f || Math.abs(mPercent - mPrePercent) >= 0.01f) {            mPercentValue = String.format("%.0f%%", mPercent * 100);            mPrePercent = mPercent;        }        canvas.drawText(mPercentValue, mCenterPoint.x, y, mPercentPaint);        if (mHint != null) {            float hy = mCenterPoint.y * 2 / 3 - (mHintPaint.descent() + mHintPaint.ascent()) / 2;            canvas.drawText(mHint.toString(), mCenterPoint.x, hy, mHintPaint);        }    }    public float getMaxValue() {        return mMaxValue;    }    public voID setMaxValue(float maxValue) {        mMaxValue = maxValue;    }    public float getValue() {        return mValue;    }    /**     * 设置当前值     *     * @param value     */    public voID setValue(float value) {        if (value > mMaxValue) {            value = mMaxValue;        }        float start = mPercent;        float end = value / mMaxValue;        Log.d(TAG, "setValue, value = " + value + ";start = " + start + "; end = " + end);        startAnimator(start, end, mDarkWaveAnimTime);    }    private voID startAnimator(final float start, float end, long animTime) {        Log.d(TAG, "startAnimator,value = " + mValue                + ";start = " + start + ";end = " + end + ";time = " + animTime);        //当start=0且end=0时,不需要启动动画        if (start == 0 && end == 0) {            return;        }        mProgressAnimator = ValueAnimator.offloat(start, end);        mProgressAnimator.setDuration(animTime);        mProgressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @OverrIDe            public voID onAnimationUpdate(ValueAnimator animation) {                mPercent = (float) animation.getAnimatedValue();                if (mPercent == 0.0f || mPercent == 1.0f) {                    stopWaveAnimator();                } else {                    startWaveAnimator();                }                mValue = mPercent * mMaxValue;                if (BuildConfig.DEBUG) {                    Log.d(TAG, "onAnimationUpdate: percent = " + mPercent                            + ";value = " + mValue);                }                invalIDate();            }        });        mProgressAnimator.start();    }    private voID startWaveAnimator() {        startlightWaveAnimator();        startDarkWaveAnimator();    }    private voID stopWaveAnimator() {        if (mDarkWaveAnimator != null && mDarkWaveAnimator.isRunning()) {            mDarkWaveAnimator.cancel();            mDarkWaveAnimator.removeAllUpdateListeners();            mDarkWaveAnimator = null;        }        if (mlightWaveAnimator != null && mlightWaveAnimator.isRunning()) {            mlightWaveAnimator.cancel();            mlightWaveAnimator.removeAllUpdateListeners();            mlightWaveAnimator = null;        }    }    private voID startlightWaveAnimator() {        if (mlightWaveAnimator != null && mlightWaveAnimator.isRunning()) {            return;        }        mlightWaveAnimator = ValueAnimator.offloat(0, 2 * mRadius);        mlightWaveAnimator.setDuration(mlightWaveAnimTime);        mlightWaveAnimator.setRepeatCount(ValueAnimator.INFINITE);        mlightWaveAnimator.setInterpolator(new linearInterpolator());        mlightWaveAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @OverrIDe            public voID onAnimationUpdate(ValueAnimator animation) {                mlightWaveOffset = (float) animation.getAnimatedValue();                postInvalIDate();            }        });        mlightWaveAnimator.addListener(new Animator.AnimatorListener() {            @OverrIDe            public voID onAnimationStart(Animator animation) {                mlightWaveOffset = 0;            }            @OverrIDe            public voID onAnimationEnd(Animator animation) {            }            @OverrIDe            public voID onAnimationCancel(Animator animation) {            }            @OverrIDe            public voID onAnimationRepeat(Animator animation) {            }        });        mlightWaveAnimator.start();    }    private voID startDarkWaveAnimator() {        if (mDarkWaveAnimator != null && mDarkWaveAnimator.isRunning()) {            return;        }        mDarkWaveAnimator = ValueAnimator.offloat(0, 2 * mRadius);        mDarkWaveAnimator.setDuration(mDarkWaveAnimTime);        mDarkWaveAnimator.setRepeatCount(ValueAnimator.INFINITE);        mDarkWaveAnimator.setInterpolator(new linearInterpolator());        mDarkWaveAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @OverrIDe            public voID onAnimationUpdate(ValueAnimator animation) {                mDarkWaveOffset = (float) animation.getAnimatedValue();                postInvalIDate();            }        });        mDarkWaveAnimator.addListener(new Animator.AnimatorListener() {            @OverrIDe            public voID onAnimationStart(Animator animation) {                mDarkWaveOffset = 0;            }            @OverrIDe            public voID onAnimationEnd(Animator animation) {            }            @OverrIDe            public voID onAnimationCancel(Animator animation) {            }            @OverrIDe            public voID onAnimationRepeat(Animator animation) {            }        });        mDarkWaveAnimator.start();    }    @OverrIDe    protected voID onDetachedFromWindow() {        super.onDetachedFromWindow();        stopWaveAnimator();        if (mProgressAnimator != null && mProgressAnimator.isRunning()) {            mProgressAnimator.cancel();            mProgressAnimator.removeAllUpdateListeners();            mProgressAnimator = null;        }    }}
/** * Created by littlejIE on 2017/2/26. */public class Constant {    public static final boolean ANTI_AliAS = true;    public static final int DEFAulT_SIZE = 150;    public static final int DEFAulT_START_ANGLE = 270;    public static final int DEFAulT_SWEEP_ANGLE = 360;    public static final int DEFAulT_ANIM_TIME = 1000;    public static final int DEFAulT_MAX_VALUE = 100;    public static final int DEFAulT_VALUE = 50;    public static final int DEFAulT_HINT_SIZE = 15;    public static final int DEFAulT_UNIT_SIZE = 30;    public static final int DEFAulT_VALUE_SIZE = 15;    public static final int DEFAulT_ARC_WIDTH = 15;    public static final int DEFAulT_WAVE_HEIGHT = 40;}
import androID.content.Context;import androID.graphics.Paint;import androID.vIEw.VIEw;/** * Created by littlejIE on 2017/2/22. */public class MiscUtil {    /**     * 测量 VIEw     *     * @param measureSpec     * @param defaultSize VIEw 的默认大小     * @return     */    public static int measure(int measureSpec, int defaultSize) {        int result = defaultSize;        int specMode = VIEw.MeasureSpec.getMode(measureSpec);        int specsize = VIEw.MeasureSpec.getSize(measureSpec);        if (specMode == VIEw.MeasureSpec.EXACTLY) {            result = specsize;        } else if (specMode == VIEw.MeasureSpec.AT_MOST) {            result = Math.min(result, specsize);        }        return result;    }    /**     * dip 转换成px     *     * @param dip     * @return     */    public static int diptopx(Context context, float dip) {        float density = context.getResources().getdisplayMetrics().density;        return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));    }    /**     * 获取数值精度格式化字符串     *     * @param precision     * @return     */    public static String getPrecisionFormat(int precision) {        return "%." + precision + "f";    }    /**     * 反转数组     *     * @param arrays     * @param <T>     * @return     */    public static <T> T[] reverse(T[] arrays) {        if (arrays == null) {            return null;        }        int length = arrays.length;        for (int i = 0; i < length / 2; i++) {            T t = arrays[i];            arrays[i] = arrays[length - i - 1];            arrays[length - i - 1] = t;        }        return arrays;    }    /**     * 测量文字高度     * @param paint     * @return     */    public static float measureTextHeight(Paint paint) {        Paint.FontMetrics FontMetrics = paint.getFontMetrics();        return (Math.abs(FontMetrics.ascent) - FontMetrics.descent);    }}
  <!-- 是否开启抗锯齿 -->    <attr name="antiAlias" format="boolean" />    <!-- 圆弧起始角度,3点钟方向为0,顺时针递增,小于0或大于360进行取余 -->    <attr name="startAngle" format="float" />    <!-- 圆弧度数 -->    <attr name="sweepAngle" format="float" />    <!-- 设置动画时间 -->    <attr name="animTime" format="integer" />    <!-- 绘制内容的数值 -->    <attr name="maxValue" format="float" />    <attr name="value" format="float" />    <!-- 绘制内容的单位 -->    <attr name="unit" format="string|reference" />    <attr name="unitSize" format="dimension" />    <attr name="unitcolor" format="color|reference" />    <!-- 绘制内容相应的提示语 -->    <attr name="hint" format="string|reference" />    <attr name="hintSize" format="dimension" />    <attr name="hintcolor" format="color|reference" />    <!-- 精度,默认为0 -->    <attr name="precision" format="integer" />    <attr name="valueSize" format="dimension" />    <attr name="valuecolor" format="color|reference" />    <!-- 圆弧颜色,设置多个可实现渐变 -->    <attr name="arccolor1" format="color|reference" />    <attr name="arccolor2" format="color|reference" />    <attr name="arccolor3" format="color|reference" />    <!-- 背景圆弧颜色,默认白色 -->    <attr name="bgArccolor" format="color|reference" />    <!-- 圆弧宽度 -->    <attr name="arcWIDth" format="dimension" />    <!-- 圆弧颜色, -->    <attr name="arccolors" format="color|reference" />    <!-- 文字的偏移量。相对于圆半径而言,默认三分之一 -->    <attr name="textOffsetPercentInRadius" format="float" />    <!-- 圆形进度条 -->    <declare-styleable name="CircleProgressbar">        <attr name="antiAlias" />        <attr name="startAngle" />        <attr name="sweepAngle" />        <attr name="animTime" />        <attr name="maxValue" />        <attr name="value" />        <attr name="precision" />        <attr name="valueSize" />        <attr name="valuecolor" />        <attr name="textOffsetPercentInRadius" />        <!-- 绘制内容相应的提示语 -->        <attr name="hint" />        <attr name="hintSize" />        <attr name="hintcolor" />        <!-- 绘制内容的单位 -->        <attr name="unit" />        <attr name="unitSize" />        <attr name="unitcolor" />        <!-- 圆弧宽度 -->        <attr name="arcWIDth" />        <attr name="arccolors" />        <!-- 背景圆弧颜色 -->        <attr name="bgArccolor" />        <!-- 背景圆弧宽度 -->        <attr name="bgArcWIDth" format="dimension" />    </declare-styleable>    <declare-styleable name="DialProgress">        <attr name="antiAlias" />        <attr name="startAngle" />        <attr name="sweepAngle" />        <attr name="animTime" />        <attr name="maxValue" />        <attr name="value" />        <attr name="precision" />        <attr name="valueSize" />        <attr name="valuecolor" />        <attr name="textOffsetPercentInRadius" />        <!-- 绘制内容的单位 -->        <attr name="unit" />        <attr name="unitSize" />        <attr name="unitcolor" />        <!-- 绘制内容相应的提示语 -->        <attr name="hint" />        <attr name="hintSize" />        <attr name="hintcolor" />        <!-- 圆弧的宽度 -->        <attr name="arcWIDth" />        <!-- 刻度的宽度 -->        <attr name="dialWIDth" format="dimension|reference" />        <!-- 刻度之间的间隔 -->        <attr name="dialintervalDegree" format="integer" />        <!-- 圆弧颜色, -->        <attr name="arccolors" />        <!-- 背景圆弧线颜色 -->        <attr name="bgArccolor" />        <!-- 刻度线颜色 -->        <attr name="dialcolor" format="color|reference" />    </declare-styleable>    <declare-styleable name="WaveProgress">        <!-- 是否开启抗锯齿 -->        <attr name="antiAlias" />        <!-- 深色水波动画时间 -->        <attr name="darkWaveAnimTime" format="integer" />        <!-- 浅色水波动画时间 -->        <attr name="lightWaveAnimTime" format="integer" />        <!-- 最大值 -->        <attr name="maxValue" />        <!-- 当前值 -->        <attr name="value" />        <attr name="valuecolor" />        <attr name="valueSize" />        <!-- 绘制内容相应的提示语 -->        <attr name="hint" />        <attr name="hintSize" />        <attr name="hintcolor" />        <!-- 圆环宽度 -->        <attr name="circleWIDth" format="dimension" />        <!-- 圆环颜色 -->        <attr name="circlecolor" format="color|reference" />        <!-- 背景圆环颜色 -->        <attr name="bgCirclecolor" format="color|reference" />        <!-- 锁定水波不随圆环进度改变,默认锁定在50%处 -->        <attr name="lockWave" format="boolean" />        <!-- 水波数量 -->        <attr name="waveNum" format="integer" />        <!-- 水波高度,峰值和谷值之和 -->        <attr name="waveHeight" format="dimension" />        <!-- 深色水波颜色 -->        <attr name="darkWavecolor" format="color|reference" />        <!-- 是否显示浅色水波 -->        <attr name="showlightWave" format="boolean" />        <!-- 浅色水波颜色 -->        <attr name="lightWavecolor" format="color|reference" />        <!-- 浅色水波的方向 -->        <attr name="lightWaveDirect" format="enum">            <enum name="L2R" value="0" />            <enum name="R2L" value="1" />        </attr>    </declare-styleable>
    <dimen name="small">5dp</dimen>    <dimen name="medium">10dp</dimen>    <dimen name="normal">15dp</dimen>    <dimen name="large">20dp</dimen>    <dimen name="xlarge">25dp</dimen>    <dimen name="xxlarge">30dp</dimen>    <!-- text size -->    <dimen name="text_size_35">35sp</dimen>    <dimen name="text_size_34">34sp</dimen>    <dimen name="text_size_33">33sp</dimen>    <dimen name="text_size_32">32sp</dimen>    <dimen name="text_size_31">31sp</dimen>    <dimen name="text_size_30">30sp</dimen>    <dimen name="text_size_29">29sp</dimen>    <dimen name="text_size_28">28sp</dimen>    <dimen name="text_size_26">26sp</dimen>    <dimen name="text_size_25">25sp</dimen>    <dimen name="text_size_24">24sp</dimen>    <dimen name="text_size_23">23sp</dimen>    <dimen name="text_size_22">22sp</dimen>    <dimen name="text_size_21">21sp</dimen>    <dimen name="text_size_20">20sp</dimen>    <dimen name="text_size_19">19sp</dimen>    <dimen name="text_size_18">18sp</dimen>    <dimen name="text_size_17">17sp</dimen>    <dimen name="text_size_16">16sp</dimen>    <dimen name="text_size_15">15sp</dimen>    <dimen name="text_size_14">14sp</dimen>    <dimen name="text_size_13">13sp</dimen>    <dimen name="text_size_12">12sp</dimen>    <dimen name="text_size_11">11sp</dimen>    <dimen name="text_size_10">10sp</dimen>    <dimen name="text_size_9">9sp</dimen>    <dimen name="text_size_8">8sp</dimen>    <dimen name="text_size_7">7sp</dimen>
<?xml version="1.0" enCoding="utf-8"?><ScrollVIEw 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:ID="@+ID/activity_main"    androID:layout_wIDth="match_parent"    androID:layout_height="match_parent"    tools:context="com.littlejIE.app.MainActivity">    <linearLayout        androID:layout_wIDth="match_parent"        androID:layout_height="wrap_content"        androID:orIEntation="vertical">        <button            androID:ID="@+ID/btn_reset_all"            androID:layout_wIDth="match_parent"            androID:layout_height="wrap_content"            androID:text="重置" />        <com.littlejIE.circleprogress.CircleProgress            androID:ID="@+ID/circle_progress_bar1"            androID:layout_wIDth="wrap_content"            androID:layout_height="wrap_content"            androID:layout_gravity="center_horizontal"            app:antiAlias="true"            app:arcWIDth="@dimen/small"            app:bgArccolor="@color/colorAccent"            app:bgArcWIDth="@dimen/small"            app:hint="截止当前已走"            app:hintSize="15sp"            app:maxValue="10000"            app:startAngle="135"            app:sweepAngle="270"            app:unit="步"            app:unitSize="15sp"            app:value="10000"            app:valueSize="25sp" />        <com.littlejIE.circleprogress.CircleProgress            androID:ID="@+ID/circle_progress_bar2"            androID:layout_wIDth="100dp"            androID:layout_height="200dp"            androID:layout_gravity="center_horizontal"            app:antiAlias="true"            app:arcWIDth="@dimen/small"            app:bgArccolor="@color/colorAccent"            app:bgArcWIDth="@dimen/small"            app:hint="百分比"            app:hintSize="@dimen/text_size_15"            app:maxValue="100"            app:startAngle="135"            app:sweepAngle="270"            app:textOffsetPercentInRadius="0.5"            app:unit="%"            app:unitSize="@dimen/text_size_15"            app:value="75"            app:valueSize="@dimen/text_size_20" />        <com.littlejIE.circleprogress.CircleProgress            androID:ID="@+ID/circle_progress_bar3"            androID:layout_wIDth="200dp"            androID:layout_height="200dp"            androID:layout_gravity="center_horizontal"            app:antiAlias="true"            app:arcWIDth="@dimen/small"            app:bgArccolor="@androID:color/darker_gray"            app:bgArcWIDth="@dimen/small"            app:hint="当前进度"            app:hintSize="@dimen/text_size_25"            app:maxValue="100"            app:startAngle="270"            app:sweepAngle="360"            app:unit="%"            app:unitSize="@dimen/text_size_25"            app:value="100"            app:valueSize="@dimen/text_size_35" />        <com.littlejIE.circleprogress.DialProgress            androID:ID="@+ID/dial_progress_bar"            androID:layout_wIDth="300dp"            androID:layout_height="300dp"            androID:layout_gravity="center_horizontal"            androID:padding="@dimen/medium"            app:animTime="1000"            app:arccolors="@array/gradIEnt_arc_color"            app:arcWIDth="@dimen/large"            app:dialintervalDegree="3"            app:dialWIDth="2dp"            app:hint="当前时速"            app:hintSize="@dimen/text_size_25"            app:maxValue="360"            app:startAngle="270"            app:sweepAngle="360"            app:unit="km/h"            app:unitSize="@dimen/text_size_25"            app:value="360"            app:valueSize="@dimen/text_size_35" />        <com.littlejIE.circleprogress.WaveProgress            androID:ID="@+ID/wave_progress_bar"            androID:layout_wIDth="300dp"            androID:layout_height="300dp"            androID:layout_gravity="center_horizontal"            app:darkWaveAnimTime="1000"            app:darkWavecolor="@color/dark"            app:lightWaveAnimTime="2000"            app:lightWavecolor="@color/light"            app:lightWaveDirect="R2L"            app:lockWave="false"            app:valueSize="@dimen/text_size_35"            app:waveHeight="30dp"            app:waveNum="1" />    </linearLayout></ScrollVIEw>

使用方法

public class MainActivity extends AppCompatActivity implements VIEw.OnClickListener {    private final static int[] colorS = new int[]{color.RED, color.YELLOW, color.GREEN, color.BLUE};    private button mBtnresetAll;    private CircleProgress mCircleProgress1, mCircleProgress2, mCircleProgress3;    private DialProgress mDialProgress;    private WaveProgress mWaveProgress;    private Random mRandom;    @OverrIDe    protected voID onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentVIEw(R.layout.activity_main);        mBtnresetAll = (button) findVIEwByID(R.ID.btn_reset_all);        mCircleProgress1 = (CircleProgress) findVIEwByID(R.ID.circle_progress_bar1);        mCircleProgress2 = (CircleProgress) findVIEwByID(R.ID.circle_progress_bar2);        mCircleProgress3 = (CircleProgress) findVIEwByID(R.ID.circle_progress_bar3);        mDialProgress = (DialProgress) findVIEwByID(R.ID.dial_progress_bar);        mWaveProgress = (WaveProgress) findVIEwByID(R.ID.wave_progress_bar);        mBtnresetAll.setonClickListener(this);        mCircleProgress1.setonClickListener(this);        mCircleProgress2.setonClickListener(this);        mCircleProgress3.setonClickListener(this);        mDialProgress.setonClickListener(this);        mWaveProgress.setonClickListener(this);        mRandom = new Random();    }    @OverrIDe    public voID onClick(VIEw v) {        switch (v.getID()) {            case R.ID.btn_reset_all:                mCircleProgress1.reset();                mCircleProgress2.reset();                mCircleProgress3.reset();                mDialProgress.reset();                break;            case R.ID.circle_progress_bar1:                mCircleProgress1.setValue(mRandom.nextInt((int) mCircleProgress1.getMaxValue()));                break;            case R.ID.circle_progress_bar2:                mCircleProgress2.setValue(mRandom.nextfloat() * mCircleProgress2.getMaxValue());                break;            case R.ID.circle_progress_bar3:                //在代码中动态改变渐变色,可能会导致颜色跳跃                mCircleProgress3.setGradIEntcolors(colorS);                mCircleProgress3.setValue(mRandom.nextfloat() * mCircleProgress3.getMaxValue());                break;            case R.ID.dial_progress_bar:                mDialProgress.setValue(mRandom.nextfloat() * mDialProgress.getMaxValue());                break;            case R.ID.wave_progress_bar:                mWaveProgress.setValue(mRandom.nextfloat() * mWaveProgress.getMaxValue());                break;        }    }}

color.xml

  <color name="dark">#803cbcb7</color>    <color name="light">#800de6e8</color>    <color name="green">#00FF00</color>    <color name="blue">#EE9A00</color>    <color name="red">#EE0000</color>    <integer-array name="gradIEnt_arc_color">        <item>@color/green</item>        <item>@color/blue</item>        <item>@color/red</item>    </integer-array>

dimens.xml

 <dimen name="activity_horizontal_margin">16dp</dimen>    <dimen name="activity_vertical_margin">16dp</dimen>

git传送阵

总结

以上是内存溢出为你收集整理的Android进度条升级篇全部内容,希望文章能够帮你解决Android进度条升级篇所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1048115.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存