package com.hdl.widget; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Shader; import android.os.Bundle; import android.os.Parcelable; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import com.hdl.widgetxm.R; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; /** * Created by JLChen on 2019/9/3 */ public class HDLWaveSeekBar extends View { private static final int DEFAULT_WAVE_BORDER_COLOR = 0xFF495780; // private static final int DEFAULT_WAVE_COLOR = 0xFFFC5733; private static final int DEFAULT_WAVE_COLOR = 0xFFFD692E; private static final int DEFAULT_WAVE_END_COLOR = 0xFFFB3140; private static final int DEFAULT_EDGE_LENGTH = 200; // 默认宽高 private Paint mBorderPaint;//圆形进度框画笔 private Paint circlePaint;//圆形进度框画笔 private Paint wavePaint;//绘制波浪画笔 private Path wavePath;//绘制波浪Path private Paint mTextPaint; //进度文字显示内容 // private Paint secondWavePaint;//绘制第二个波浪的画笔 private Bitmap bitmap;//缓存bitmap private Canvas bitmapCanvas; private float waveWidth;//波浪宽度 private float waveHeight;//波浪高度 private int waveNum;//波浪组的数量(一次起伏为一组) private float waveMovingDistance;//波浪平移的距离 private float defaultSize;//自定义View默认的宽高 private float mPercent;//进度条占比 private int mProgress;//可以更新的进度条数值 // private int waveColor;//波浪颜色 // private int secondWaveColor;//第二层波浪颜色 private int bgColor;//背景进度颜色 private int mBorderColor; //背景边框框颜色 private float mBorderWidth; //背景边框框宽度 private int mPadding = 10; private boolean isClickable = true; private float mSeekBarWidth; private float mSeekBarHeight; private float mWaveViewWidth;//重新测量后View实际的宽 private float mWaveViewHeight;//重新测量后View实际的高 private int mMaxValue; // 最大数值 private int mMinValue; // 最小数值 private float mCenterX; // 圆弧 SeekBar 中心点 X private float mCenterY; // 圆弧 SeekBar 中心点 Y private String mProgressBarUnitSring; //进度单位符号 private static final String DEFAULT_ARC_PROGRESS_BAR_UNIT_STRING = "%"; // 默认显示单位 private float mWaveLeftAndTop,mWaveRight,mWaveBottom; private float mBorderLeftAndTop; private boolean isProgressTextShow = true; private int mCornerRadius; //圆角半径大小 private boolean isDrawSecondWave; private float nowY; private int[] mArcProgressBarColors; // 当前进度渐变颜色数组 public HDLWaveSeekBar(Context context) { this(context, null); } public HDLWaveSeekBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HDLWaveSeekBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setSaveEnabled(true); setLayerType(LAYER_TYPE_SOFTWARE, null); initAttrs(context, attrs); initData(); initPaint(); } private void initData() { defaultSize = dp2px(100); mBorderWidth = dp2px(2); mPadding = dp2px(10); waveNum =(int) Math.ceil(Double.parseDouble(String.valueOf(defaultSize / waveWidth / 2))); waveMovingDistance = 0; mPercent = 0.0f; mProgress = 0; isDrawSecondWave = false; mMaxValue = 100; mMinValue = 0; mCornerRadius = dp2px(10); mProgressBarUnitSring = DEFAULT_ARC_PROGRESS_BAR_UNIT_STRING; isProgressTextShow = true; mArcProgressBarColors = new int[]{DEFAULT_WAVE_COLOR,DEFAULT_WAVE_END_COLOR}; } private void initPaint() { wavePath = new Path(); wavePaint = new Paint(); wavePaint.setColor(DEFAULT_WAVE_COLOR); wavePaint.setAntiAlias(true);//设置抗锯齿 wavePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); // secondWavePaint = new Paint(); // secondWavePaint.setColor(secondWaveColor); // secondWavePaint.setAntiAlias(true);//设置抗锯齿 // secondWavePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));//因为要覆盖在第一层波浪上,且要让半透明生效,所以选此模式 circlePaint = new Paint(); circlePaint.setColor(bgColor); circlePaint.setAntiAlias(true);//设置抗锯齿 mBorderPaint = new Paint(); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setColor(mBorderColor); mBorderPaint.setAntiAlias(true);//设置抗锯齿 mBorderPaint.setStrokeWidth(mBorderWidth); initTextPanit(); } // 初始化拖动按钮顶部文字画笔和进度圆弧画笔 private void initTextPanit() { mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setStrokeWidth(1); mTextPaint.setTextSize(getTextSizeDip(20)); mTextPaint.setColor(Color.BLACK); mTextPaint.setTextAlign(Paint.Align.CENTER); } // public HDLWaveSeekBar(Context context, @Nullable AttributeSet attrs) { // super(context, attrs); // init(context,attrs); // } private void initAttrs(Context context,AttributeSet attrs){ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HDLWaveSeekBar); waveWidth = typedArray.getDimension(R.styleable.HDLWaveSeekBar_wave_width, dp2px(80)); waveHeight = typedArray.getDimension(R.styleable.HDLWaveSeekBar_wave_height,dp2px(15)); // waveColor = typedArray.getColor(R.styleable.HDLWaveSeekBar_wave_color, DEFAULT_WAVE_COLOR); // secondWaveColor = typedArray.getColor(R.styleable.HDLWaveSeekBar_second_wave_color,getResources().getColor(R.color.light)); bgColor = typedArray.getColor(R.styleable.HDLWaveSeekBar_wave_bg_color,Color.WHITE); mBorderColor = typedArray.getColor(R.styleable.HDLWaveSeekBar_wave_border_color, DEFAULT_WAVE_BORDER_COLOR); typedArray.recycle(); } private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics()); } private float getTextSizeDip(float value) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics()); } private void onWaveSizeChange(){ mWaveViewWidth = mSeekBarWidth - mPadding*4 - mBorderWidth*2; mWaveViewHeight = mSeekBarHeight - mPadding*4 - mBorderWidth*2; mWaveLeftAndTop = mPadding*2 + mBorderWidth; mWaveRight = mSeekBarWidth - mPadding*2 - mBorderWidth; mWaveBottom = mSeekBarHeight - mPadding*2 - mBorderWidth; mBorderLeftAndTop = mPadding + mBorderWidth/2; waveNum = (int) Math.ceil(Double.parseDouble(String.valueOf(mWaveViewWidth / waveWidth / 2))); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int ws = MeasureSpec.getSize(widthMeasureSpec); //取出宽度的确切数值 int wm = MeasureSpec.getMode(widthMeasureSpec); //取出宽度的测量模式 int hs = MeasureSpec.getSize(heightMeasureSpec); //取出高度的确切数值 int hm = MeasureSpec.getMode(heightMeasureSpec); //取出高度的测量模 if (wm == MeasureSpec.UNSPECIFIED) { wm = MeasureSpec.EXACTLY; ws = dp2px(DEFAULT_EDGE_LENGTH); } else if (wm == MeasureSpec.AT_MOST) { wm = MeasureSpec.EXACTLY; ws = Math.min(dp2px(DEFAULT_EDGE_LENGTH), ws); } if (hm == MeasureSpec.UNSPECIFIED) { hm = MeasureSpec.EXACTLY; hs = dp2px(DEFAULT_EDGE_LENGTH); } else if (hm == MeasureSpec.AT_MOST) { hm = MeasureSpec.EXACTLY; hs = Math.min(dp2px(DEFAULT_EDGE_LENGTH), hs); } setMeasuredDimension(MeasureSpec.makeMeasureSpec(ws, wm), MeasureSpec.makeMeasureSpec(hs, hm)); mSeekBarHeight = hs; mSeekBarWidth = ws; mCenterX = mSeekBarWidth/2; mCenterY = mSeekBarHeight/2; onWaveSizeChange(); } private int measureSize(int defaultSize,int measureSpec) { int result = defaultSize; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } return result; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 计算在当前大小下,内容应该显示的大小和起始位置 int safeW = w - getPaddingLeft() - getPaddingRight(); int safeH = h - getPaddingTop() - getPaddingBottom(); mSeekBarHeight = safeH; mSeekBarWidth = safeW; mCenterX = mSeekBarWidth/2; mCenterY = mSeekBarHeight/2; onWaveSizeChange(); // Log.i("getCurrentProgress ","mSeekBarHeight :Y " + mSeekBarHeight + " mSeekBarWidth:"+mSeekBarWidth); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); //画圆角矩形 RectF rectF = new RectF(mBorderLeftAndTop, mBorderLeftAndTop, mSeekBarWidth - mBorderLeftAndTop, mSeekBarHeight-mBorderLeftAndTop); canvas.drawRoundRect(rectF, mCornerRadius, mCornerRadius, mBorderPaint); // //画圆角矩形 // RectF rectF2 = new RectF(10, 10, mWaveViewWidth-20, mWaveViewWidth-20); // canvas.drawRoundRect(rectF2, 80, 80, circlePaint); // canvas.drawPath(getWavePath(),wavePaint); // canvas.restore(); bitmap = Bitmap.createBitmap((int)mSeekBarWidth, (int)mSeekBarHeight, Bitmap.Config.ARGB_8888); bitmapCanvas = new Canvas(bitmap); RectF rectF2 = new RectF(mWaveLeftAndTop, mWaveLeftAndTop, mWaveRight, mWaveBottom); bitmapCanvas.drawRoundRect(rectF2, mCornerRadius, mCornerRadius, circlePaint); resetmArcProgressBarColor();//实现渐变效果 // bitmapCanvas.drawCircle(mWaveViewWidth/2, mWaveViewWidth/2, mWaveViewWidth/2, circlePaint); bitmapCanvas.drawPath(getWavePath(), wavePaint); // if(isDrawSecondWave){ // bitmapCanvas.drawPath(getSecondWavePath(),secondWavePaint); // } canvas.drawBitmap(bitmap, 0, 0, null); if(isProgressTextShow) { if(mPercent>0.6){ mTextPaint.setColor(Color.WHITE); }else { mTextPaint.setColor(Color.BLACK); } canvas.drawText(String.valueOf(getProgress()) + mProgressBarUnitSring, mCenterX, mCenterY, mTextPaint); } canvas.restore(); } /** * 重置 mArcProgressBarColors 颜色 */ private void resetmArcProgressBarColor() { LinearGradient gradient = new LinearGradient(mBorderLeftAndTop, mBorderLeftAndTop, mSeekBarWidth - mBorderLeftAndTop, mSeekBarHeight-mBorderLeftAndTop, mArcProgressBarColors, null, Shader.TileMode.MIRROR); wavePaint.setShader(gradient); } //--- 初始化结束 ------------------------------------------------------------------------------- //--- 状态存储 --------------------------------------------------------------------------------- private static final String KEY_PROGRESS_PRESENT = "PRESENTWAVE"; // 用于存储和获取当前百分比 @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable("superState", super.onSaveInstanceState()); bundle.putFloat(KEY_PROGRESS_PRESENT, mProgress); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; this.mProgress = bundle.getInt(KEY_PROGRESS_PRESENT); state = bundle.getParcelable("superState"); } if (null != mOnProgressChangeListener) { mOnProgressChangeListener.onProgressChanged(this, this.mProgress, false); } super.onRestoreInstanceState(state); } //--- 状态存储结束 ----------------------------------------------------------------------------- private Path getWavePath(){ // float changeWaveHeight = (1 - mPercent) * waveHeight; float changeWaveHeight = waveHeight; nowY = (1-mPercent)*mWaveViewHeight + mWaveLeftAndTop; wavePath.reset(); //移动到右上方,也就是p0点 wavePath.moveTo(mWaveRight, nowY); //移动到右下方,也就是p1点 wavePath.lineTo(mWaveRight, mWaveBottom); //移动到左下边,也就是p2点 wavePath.lineTo(mWaveLeftAndTop, mWaveBottom); //移动到左上方,也就是p3点 //wavePath.lineTo(0, (1-mPercent)*mWaveViewWidth); // wavePath.lineTo(-waveMovingDistance, (1-mPercent)*mSeekBarHeight); if(mPercent == 0 || mPercent ==1){ wavePath.lineTo(mWaveLeftAndTop, nowY); }else { wavePath.lineTo(-waveMovingDistance, nowY); //从p3开始向p0方向绘制波浪曲线 for (int i = 0; i < waveNum * 2; i++) { wavePath.rQuadTo(waveWidth / 2, changeWaveHeight, waveWidth, 0); wavePath.rQuadTo(waveWidth / 2, -changeWaveHeight, waveWidth, 0); } } //将path封闭起来 wavePath.close(); return wavePath; } private boolean mCanDrag = false; // 是否允许拖动 private boolean moved = false; // 是否允许 private int lastProgress = -1; @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); if(!isClickable) return false; int action = event.getActionMasked(); switch (action) { case ACTION_DOWN: moved = false; judgeCanDrag(event); if (null != mOnProgressChangeListener) { mOnProgressChangeListener.onStartTrackingTouch(this); } break; case ACTION_MOVE: if (!mCanDrag) { break; } setCurrentPercent(event); // 事件回调 if (null != mOnProgressChangeListener && mProgress != lastProgress) { mOnProgressChangeListener.onProgressChanged(this, mProgress, true); lastProgress = mProgress; } moved = true; break; case ACTION_UP: case ACTION_CANCEL: if(!moved){ if (isInArcProgress(event.getX(),event.getY())) { setCurrentPercent(event); } } if (null != mOnProgressChangeListener) { mOnProgressChangeListener.onStopTrackingTouch(this); } break; } invalidate(); return true; } // 判断是否允许拖动 private void judgeCanDrag(MotionEvent event) { if(isInArcProgress(event.getX(),event.getY())){ mCanDrag = true; }else { mCanDrag = false; } } private void setCurrentPercent(MotionEvent event) { // Log.i("getCurrentProgress ","getCurrentProgress :Y " + event.getY() + " X:"+event.getX()); float progressY = event.getY() - mWaveLeftAndTop; float progress = progressY /mWaveViewHeight; progress = 1 - progress; if (progress < 0) progress = 0; if (progress > 1) progress = 1; mPercent = progress; mProgress = (int) (mPercent * (mMaxValue - mMinValue)) + mMinValue; waveMovingDistance = mPercent * 500; // Log.i("getCurrentProgress ","getCurrentProgress :mProgress " + mProgress); } private boolean isInArcProgress(float px ,float py) { if(px < 0 || px > mSeekBarWidth || py < 0 || py > mSeekBarHeight){ return false; }else { return true; } } // endregion ----------------------------------------------------------------------------------- // region 状态回调 ------------------------------------------------------------------------------ private HDLWaveSeekBar.OnProgressChangeListener mOnProgressChangeListener; public void setOnProgressChangeListener(HDLWaveSeekBar.OnProgressChangeListener onProgressChangeListener) { mOnProgressChangeListener = onProgressChangeListener; } public interface OnProgressChangeListener { /** * 进度发生变化 * * @param seekBar 拖动条 * @param progress 当前进度数值 * @param isUser 是否是用户操作, true 表示用户拖动, false 表示通过代码设置 */ void onProgressChanged(HDLWaveSeekBar seekBar, int progress, boolean isUser); /** * 用户开始拖动 * * @param seekBar 拖动条 */ void onStartTrackingTouch(HDLWaveSeekBar seekBar); /** * 用户结束拖动 * * @param seekBar 拖动条 */ void onStopTrackingTouch(HDLWaveSeekBar seekBar); } // endregion ----------------------------------------------------------------------------------- //****************************对外接口**************************************************** /** * 设置控件是否可用点击 * @param isClickable */ public void setIsClickable(boolean isClickable) { this.isClickable = isClickable; } public int getProgress() { return mProgress; } public void setProgress(int progress) { System.out.println("setProgress = " + progress); if (progress > mMaxValue) progress = mMaxValue; if (progress < mMinValue) progress = mMinValue; mProgress = progress; mPercent = (progress - mMinValue) * 1.0f / (mMaxValue - mMinValue); // System.out.println("setProgress present = " + progress); // if (null != mOnProgressChangeListener) { // mOnProgressChangeListener.onProgressChanged(this, progress, false); // } postInvalidate(); } /** * 进度文字大小 * @param textSize */ public void setProgressTextSize(int textSize){ mTextPaint.setTextSize(getTextSizeDip(textSize)); } /** * 进度文字颜色 * @param textPaintColor */ public void setProgressTextColor(int textPaintColor){ mTextPaint.setColor(textPaintColor); } /** * 设置进度显示值单位 * * @param progressBarUnitSring 进度显示值单位 */ public void setProgressBarUnitSring(String progressBarUnitSring) { mProgressBarUnitSring = progressBarUnitSring; } /** * 设置最大数值 * * @param max 最大数值 */ public void setMaxValue(int max) { mMaxValue = max; } /** * 设置最小数值 * * @param min 最小数值 */ public void setMinValue(int min) { mMinValue = min; } public void setBorderWidth(int borderWidth) { // mBorderWidth = dp2px(borderWidth); mBorderWidth = borderWidth; mBorderPaint.setStrokeWidth(mBorderWidth); onWaveSizeChange(); postInvalidate(); } // // public void setWaveColor(int mWaveColor){ // waveColor = mWaveColor; // wavePaint.setColor(waveColor); // // } /** * 设置颜色 * 3个颜色 渐变效果 * @param colors 颜色 */ public void setProgressBarColors(int[] colors) { if(colors.length < 2) return; mArcProgressBarColors = colors; resetmArcProgressBarColor(); postInvalidate(); } /** * 设置颜色 单种颜色 * @param colors 颜色 */ public void setProgressBarColor(int colors) { int[] colorsArray = new int[]{colors, colors}; mArcProgressBarColors = colorsArray; resetmArcProgressBarColor(); postInvalidate(); } public void setWaveBorderColor(int mmBorderColor){ mBorderColor = mmBorderColor; mBorderPaint.setColor(mBorderColor); } public void setWaveBgColor(int mBgColor){ bgColor = mBgColor; circlePaint.setColor(bgColor); } public void setWavePadding(int mmPadding){ // mPadding = dp2px(mmPadding); mPadding = mmPadding; onWaveSizeChange(); } public void setCornerRadius(int mmCornerRadius){ // mCornerRadius = dp2px(mmCornerRadius); mCornerRadius = mmCornerRadius; } public void setProgressTextShow(boolean progressTextShow) { isProgressTextShow = progressTextShow; } /** *当前 进度Y坐标 */ public float getProgressY() { return nowY; } }