渐变色圆形流量球,渐变色圆形进度条

来源:互联网 发布:淘宝运营工资怎么样 编辑:程序博客网 时间:2024/05/21 18:40

效果图

这里写图片描述
这里写图片描述
这里写图片描述

代码如下

package com.onething.balltest;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    private WaveProgress waterView;    private ImageView iv_ball_bg;    private TextView tv_unit, tv_restflow;    private Button btn_yellow, btn_red;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final int yellowDark = getResources().getColor(R.color.yellow_dark);        final int yellowLight = getResources().getColor(R.color.yellow_light);        final int reaDark = getResources().getColor(R.color.red_dark);        final int reaLight = getResources().getColor(R.color.red_light);        final int blueDark = getResources().getColor(R.color.blue_dark);        final int blueLight = getResources().getColor(R.color.blue_light);        waterView = (WaveProgress) findViewById(R.id.waterView);        iv_ball_bg = (ImageView) findViewById(R.id.iv_ball_bg);        tv_unit = (TextView) findViewById(R.id.tv_unit);        tv_restflow = (TextView) findViewById(R.id.tv_restflow);        btn_red = (Button) findViewById(R.id.btn_red);        btn_yellow = (Button) findViewById(R.id.btn_yellow);        waterView.setMaxValue(100f);        waterView.setValue(55f);        findViewById(R.id.btn_blue).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                waterView.setWaveColor(blueDark, blueLight);                iv_ball_bg.setBackgroundResource(R.mipmap.blue_ball);                tv_restflow.setTextColor(getResources().getColor(R.color.blue_tint));                tv_unit.setTextColor(getResources().getColor(R.color.blue_tint));            }        });        btn_yellow.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                waterView.setWaveColor(yellowDark, yellowLight);                iv_ball_bg.setBackgroundResource(R.mipmap.yello_ball);                tv_restflow.setTextColor(getResources().getColor(R.color.yellow_tint));                tv_unit.setTextColor(getResources().getColor(R.color.yellow_tint));            }        });        btn_red.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                waterView.setWaveColor(reaDark, reaLight);                iv_ball_bg.setBackgroundResource(R.mipmap.red_ball);                tv_restflow.setTextColor(getResources().getColor(R.color.red_tint));                tv_unit.setTextColor(getResources().getColor(R.color.red_tint));            }        });    }}

view代码如下

package com.onething.balltest;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;/** * 水波进度条 * 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;    private int DarkWaveColor;//动态设置波浪颜色    private int LightWaveColor;//动态设置波浪颜色    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, mLightWaveColor);        mBgCircleColor = typedArray.getColor(R.styleable.WaveProgress_bgCircleColor, mLightWaveColor);        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, DarkWaveColor);        mLightWaveColor = typedArray.getColor(R.styleable.WaveProgress_lightWaveColor, LightWaveColor);        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);        // TODO: 2017/7/5 渐变色//        LinearGradient gradient = new LinearGradient(250, 0, 250, 300, mDarkWaveColor, mLightWaveColor, MIRROR);//        RadialGradient radialGradient = new RadialGradient(390, 300, 120f, mDarkWaveColor, mLightWaveColor, MIRROR);//        mWavePaint.setShader(radialGradient);        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, 360, false, mCirclePaint);        canvas.restore();    }    /**     * 绘制深色波浪(贝塞尔曲线)     *     * @param canvas     */    private void drawDarkWave(Canvas canvas) {        mWavePaint.setColor(DarkWaveColor);        drawWave(canvas, mWavePaint, mDarkPoints, mDarkWaveOffset);    }    /**     * 绘制浅色波浪(贝塞尔曲线)     *     * @param canvas     */    private void drawLightWave(Canvas canvas) {        mWavePaint.setColor(LightWaveColor);        //从右向左的水波位移应该被减去        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 void drawProgress(Canvas canvas) {        float y = mCenterPoint.y - (mPercentPaint.descent() + mPercentPaint.ascent()) / 2;//        canvas.drawText(String.format("%.0f%%", mPercent * 100), mCenterPoint.x, y, mPercentPaint);// TODO: 2017/7/6 绘制球体中间字体        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;    }    /**     * 设置当前值     *     * @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);    }    public void setWaveColor(int darkWaveColor, int lightWaveColor) {        DarkWaveColor = darkWaveColor;        LightWaveColor = lightWaveColor;    }    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 = null;        }        if (mLightWaveAnimator != null && mLightWaveAnimator.isRunning()) {            mLightWaveAnimator.cancel();            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();        }    }}

下载地址这里写链接内容

原创粉丝点击