package cn.modificator.waterwave_progress; import java.lang.ref.WeakReference; import android.annotation.SuppressLint; import android.content.Context; 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.graphics.Region; import android.graphics.Path.Direction; import android.graphics.Region.Op; import android.os.Handler; import android.os.Message; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.ProgressBar; /** * @author Administrator * */ public class WaterWaveProgress extends View { // 水的画笔 // 画圆环的画笔// 进度百分比的画笔 private Paint mPaintWater = null, mRingPaint = null, mTextPaint = null; // 圆环颜色 // 圆环背景颜色 // 当前进度 //水波颜色 // 水波背景色 //进度条和水波之间的距离 //进度百分比字体大小 // //进度百分比字体颜色 private int mRingColor, mRingBgColor, mWaterColor, mWaterBgColor, mFontSize, mTextColor; // 进度 //浪峰个数 float crestCount = 1.5f; int mProgress = 10, mMaxProgress = 100; // 画布中心点 private Point mCenterPoint; // 圆环宽度 private float mRingWidth, mProgress2WaterWidth; // 是否显示进度条 //是否显示进度百分比 private boolean mShowProgress = false, mShowNumerical = true; /** 产生波浪效果的因子 */ private long mWaveFactor = 0L; /** 正在执行波浪动画 */ private boolean isWaving = false; /** 振幅 */ private float mAmplitude = 30.0F; // 20F /** 波浪的速度 */ private float mWaveSpeed = 0.070F; // 0.020F /** 水的透明度 */ private int mWaterAlpha = 255; // 255 WaterWaveAttrInit attrInit; private MyHandler mHandler = null; private static class MyHandler extends Handler { private WeakReference<WaterWaveProgress> mWeakRef = null; private int refreshPeriod = 100; public MyHandler(WaterWaveProgress host) { mWeakRef = new WeakReference<WaterWaveProgress>(host); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (mWeakRef.get() != null) { mWeakRef.get().invalidate(); sendEmptyMessageDelayed(0, refreshPeriod); } } } public WaterWaveProgress(Context paramContext) { super(paramContext); } public WaterWaveProgress(Context context, AttributeSet attributeSet) { this(context, attributeSet, 0); } public WaterWaveProgress(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); attrInit = new WaterWaveAttrInit(context, attrs, defStyleAttr); init(context); } @SuppressLint("NewApi") private void init(Context context) { mCenterPoint = new Point(); mRingColor = attrInit.getProgressColor(); mRingBgColor = attrInit.getProgressBgColor(); mWaterColor = attrInit.getWaterWaveColor(); mWaterBgColor = attrInit.getWaterWaveBgColor(); mRingWidth = attrInit.getProgressWidth(); mProgress2WaterWidth = attrInit.getProgress2WaterWidth(); mShowProgress = attrInit.isShowProgress(); mShowNumerical = attrInit.isShowNumerical(); mFontSize = attrInit.getFontSize(); mTextColor = attrInit.getTextColor(); mProgress = attrInit.getProgress(); mMaxProgress = attrInit.getMaxProgress(); // 如果手机版本在4.0以上,则开启硬件加速 if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) { setLayerType(View.LAYER_TYPE_HARDWARE, null); // setLayerType(View.LAYER_TYPE_SOFTWARE, null); } mRingPaint = new Paint(); mRingPaint.setAntiAlias(true); mRingPaint.setColor(mRingColor); // 圆环颜色 mRingPaint.setStyle(Paint.Style.STROKE); mRingPaint.setStrokeWidth(mRingWidth); // 圆环宽度 mPaintWater = new Paint(); mPaintWater.setStrokeWidth(1.0F); mPaintWater.setColor(mWaterColor); // mPaintWater.setColor(getResources().getColor(mWaterColor)); mPaintWater.setAlpha(mWaterAlpha); mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setColor(mTextColor); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setTextSize(mFontSize); mHandler = new MyHandler(this); } public void animateWave() { if (!isWaving) { mWaveFactor = 0L; isWaving = true; mHandler.sendEmptyMessage(0); } } @SuppressLint({ "DrawAllocation", "NewApi" }) protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 获取整个View(容器)的宽、高 int width = getWidth(); int height = getHeight(); width = height = (width < height) ? width : height; mAmplitude = width / 20f; mCenterPoint.x = width / 2; mCenterPoint.y = height / 2; { // 重新设置进度条的宽度和水波与进度条的距离,,至于为什么写在这,我脑袋抽了可以不 mRingWidth = mRingWidth == 0 ? width / 20 : mRingWidth; mProgress2WaterWidth = mProgress2WaterWidth == 0 ? mRingWidth * 0.6f : mProgress2WaterWidth; mRingPaint.setStrokeWidth(mRingWidth); mTextPaint.setTextSize(mFontSize == 0 ? width / 5 : mFontSize); if (VERSION.SDK_INT==VERSION_CODES.JELLY_BEAN) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); }else { setLayerType(View.LAYER_TYPE_HARDWARE, null); } } RectF oval = new RectF(); oval.left = mRingWidth / 2; oval.top = mRingWidth / 2; oval.right = width - mRingWidth / 2; oval.bottom = height - mRingWidth / 2; if (isInEditMode()) { mRingPaint.setColor(mRingBgColor); canvas.drawArc(oval, -90, 360, false, mRingPaint); mRingPaint.setColor(mRingColor); canvas.drawArc(oval, -90, 90, false, mRingPaint); canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, mCenterPoint.x - mRingWidth - mProgress2WaterWidth, mPaintWater); return; } // 如果没有执行波浪动画,或者也没有指定容器宽高,就画个简单的矩形 if ((width == 0) || (height == 0) || isInEditMode()) { canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, width / 2 - mProgress2WaterWidth - mRingWidth, mPaintWater); return; } // 水与边框的距离 float waterPadding = mShowProgress ? mRingWidth + mProgress2WaterWidth : 0; // 水最高处 int waterHeightCount = mShowProgress ? (int) (height - waterPadding * 2) : height; // 重新生成波浪的形状 mWaveFactor++; if (mWaveFactor >= Integer.MAX_VALUE) { mWaveFactor = 0L; } // 画进度条背景 mRingPaint.setColor(mRingBgColor); // canvas.drawArc(oval, -90, 360, false, mRingPaint); // //和下面效果一样,只不过这个是画个360度的弧,下面是画圆环 canvas.drawCircle(width / 2, width / 2, waterHeightCount / 2 + waterPadding - mRingWidth / 2, mRingPaint); mRingPaint.setColor(mRingColor); // 100为 总进度 canvas.drawArc(oval, -90, (mProgress*1f) / mMaxProgress * 360f, false, mRingPaint); // 计算出水的高度 float waterHeight = waterHeightCount * (1 - (mProgress*1f) / mMaxProgress) + waterPadding; int staticHeight = (int) (waterHeight + mAmplitude); Path mPath = new Path(); mPath.reset(); if (mShowProgress) { mPath.addCircle(width / 2, width / 2, waterHeightCount / 2, Direction.CCW); } else { mPath.addCircle(width / 2, width / 2, waterHeightCount / 2, Direction.CCW); } // canvas添加限制,让接下来的绘制都在园内 canvas.clipPath(mPath, Op.REPLACE); Paint bgPaint = new Paint(); bgPaint.setColor(mWaterBgColor); // 绘制背景 canvas.drawRect(waterPadding, waterPadding, waterHeightCount + waterPadding, waterHeightCount + waterPadding, bgPaint); // 绘制静止的水 canvas.drawRect(waterPadding, staticHeight, waterHeightCount + waterPadding, waterHeightCount + waterPadding, mPaintWater); // 待绘制的波浪线的x坐标 int xToBeDrawed = (int) waterPadding; int waveHeight = (int) (waterHeight - mAmplitude * Math.sin(Math.PI * (2.0F * (xToBeDrawed + (mWaveFactor * width) * mWaveSpeed)) / width)); // 波浪线新的高度 int newWaveHeight = waveHeight; while (true) { if (xToBeDrawed >= waterHeightCount + waterPadding) { break; } // 根据当前x值计算波浪线新的高度 newWaveHeight = (int) (waterHeight - mAmplitude * Math.sin(Math.PI * (crestCount * (xToBeDrawed + (mWaveFactor * waterHeightCount) * mWaveSpeed)) / waterHeightCount)); // 先画出梯形的顶边 canvas.drawLine(xToBeDrawed, waveHeight, xToBeDrawed + 1, newWaveHeight, mPaintWater); // 画出动态变化的柱子部分 canvas.drawLine(xToBeDrawed, newWaveHeight, xToBeDrawed + 1, staticHeight, mPaintWater); xToBeDrawed++; waveHeight = newWaveHeight; } if (mShowNumerical) { String progressTxt = String.format("%.0f", (mProgress*1f) / mMaxProgress * 100f) + "%"; float mTxtWidth = mTextPaint.measureText(progressTxt, 0, progressTxt.length()); canvas.drawText(progressTxt, mCenterPoint.x - mTxtWidth / 2, mCenterPoint.x * 1.5f - mFontSize / 2, mTextPaint); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = widthMeasureSpec; int height = heightMeasureSpec; width = height = (width < height) ? width : height; setMeasuredDimension(width, height); } /** * 设置波浪的振幅 */ public void setAmplitude(float amplitude) { mAmplitude = amplitude; } /** * 设置水的透明度 * * @param alpha * 透明的百分比,值为0到1之间的小数,越接近0越透明 */ public void setWaterAlpha(float alpha) { mWaterAlpha = (int) (255.0F * alpha); mPaintWater.setAlpha(mWaterAlpha); } /** 设置水的颜色 */ public void setWaterColor(int color) { mWaterColor = color; } /** * 设置当前进度 */ public void setProgress(int progress) { progress = progress > 100 ? 100 : progress < 0 ? 0 : progress; mProgress = progress; invalidate(); } /** 获取进度 动画时会用到 */ public int getProgress() { return mProgress; } /** * 设置波浪速度 */ public void setWaveSpeed(float speed) { mWaveSpeed = speed; } /** * 是否显示进度条 * * @param boolean */ public void setShowProgress(boolean b) { mShowProgress = b; } /** * 是否显示进度值 * * @param boolean */ public void setShowNumerical(boolean b) { mShowNumerical = b; } /** * 设置进度条前景色 * * @param mRingColor */ public void setmRingColor(int mRingColor) { this.mRingColor = mRingColor; } /** * 设置进度条背景色 * * @param mRingBgColor */ public void setmRingBgColor(int mRingBgColor) { this.mRingBgColor = mRingBgColor; } /** * 设置水波颜色 * * @param mWaterColor */ public void setmWaterColor(int mWaterColor) { this.mWaterColor = mWaterColor; } /** * 设置水波背景色 * * @param mWaterBgColor */ public void setWaterBgColor(int mWaterBgColor) { this.mWaterBgColor = mWaterBgColor; } /** * 设置进度值显示字体大小 * * @param mFontSize */ public void setFontSize(int mFontSize) { this.mFontSize = mFontSize; } /** * 设置进度值显示字体颜色 * * @param mTextColor */ public void setTextColor(int mTextColor) { this.mTextColor = mTextColor; } /** * 设置进度条最大值 * * @param mMaxProgress */ public void setMaxProgress(int mMaxProgress) { this.mMaxProgress = mMaxProgress; } /** * 设置浪峰个数 * * @param crestCount */ public void setCrestCount(float crestCount) { this.crestCount = crestCount; } /** * 设置进度条宽度 * * @param mRingWidth */ public void setRingWidth(float mRingWidth) { this.mRingWidth = mRingWidth; } /** * 设置水波到进度条之间的距离 * * @param mProgress2WaterWidth */ public void setProgress2WaterWidth(float mProgress2WaterWidth) { this.mProgress2WaterWidth = mProgress2WaterWidth; } }