渐变色圆形流量球,渐变色圆形进度条
来源:互联网 发布:淘宝运营工资怎么样 编辑:程序博客网 时间: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(); } }}
下载地址这里写链接内容
阅读全文
0 0
- 渐变色圆形流量球,渐变色圆形进度条
- 自定义View之渐变色圆形进度条
- HTML5 canvas带渐变色的圆形进度条动画
- Andorid自定义圆形渐变色进度条的从实现到开源
- Andorid 自定义圆形渐变色进度条的从实现到开源
- Android 自定义圆形带刻度渐变色的进度条
- Andorid自定义圆形渐变色进度条的从实现到开源
- Android自定义圆形渐变进度条
- 【前端插件】渐变圆形进度条
- WPF 圆形按钮 渐变色
- Android之自定义圆形渐变、条形进度条
- 自定义圆形进度条控件,及圆形渐变颜色实现
- svg圆形渐变
- 渐变圆形及矩形
- html5圆形渐变
- Canvas 圆形渐变
- 圆形径向渐变按钮
- Swift 圆形渐变进度条 支持事件 支持XIB和StoryBoard
- git创建分支以及远程下载提交项目
- 消除尾递归
- 数组与矩阵
- 高斯牛顿(Gauss Newton)、列文伯格-马夸尔特(Levenberg-Marquardt)最优化算法与VSLAM
- android监听usb的插入与拔出
- 渐变色圆形流量球,渐变色圆形进度条
- mysql创建用户及权限管理
- xib自定义单元格的高度
- js排序
- stm32 基于TIM1定时器的PWM输出
- IIFE(立即执行函数表达式)
- Laravel5.3初步使用一(环境搭配(AppServ集成)、数据库配置、目录介绍)
- sh小结
- iOS Xcode工程目录的 folder 和 group的区别(蓝色和黄色文件夹的区别)