package com.hdl.widget; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.os.Bundle; import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; 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/12/5 */ public class HDLDiyImageSeekBar extends View { private static final int DEFAULT_EDGE_LENGTH = 200; // 默认宽高 private Paint mTextPaint; //进度文字显示内容 private Paint mImagePaint; // private Paint mProgressPaint; // // private float defaultSize;//自定义View默认的宽高 private float mPercent;//进度条占比 private int mProgress;//可以更新的进度条数值 private int mPadding = 10; private boolean isClickable = true; private float mSeekBarWidth; private float mSeekBarHeight; private float mDiySeekBarViewWidth;//重新测量后View实际的宽 private int mDiySeekBarViewHeight;//重新测量后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 boolean isProgressTextShow = true; // private int mCornerRadius; //圆角半径大小 private float nowX; private float buttonWidth = 10; private float mDiySeekBarPaddingTop = 5; // private float mDiySeekBarPaddingBottom = 5; // private Bitmap bgBitmapButton; private boolean isOffline = false; private Paint offlinePaint; private int offlineRadius = 10; private int mProgressBarColor = Color.YELLOW; //当前进度颜色 private int mBackgroundColor = HDLUtlisXM.DEFAULT_OFFLINE_COLOR; //当前背景颜色 public HDLDiyImageSeekBar(Context context) { this(context, null); } public HDLDiyImageSeekBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HDLDiyImageSeekBar(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); mPadding = dp2px(10); buttonWidth = dp2px(10); offlineRadius = dp2px(5); mPercent = 0.0f; mProgress = 0; mMaxValue = 100; mMinValue = 0; mDiySeekBarViewHeight = dp2px(10); buttonWidth = mDiySeekBarViewHeight * 2; // mCornerRadius = dp2px(2); mProgressBarUnitSring = DEFAULT_ARC_PROGRESS_BAR_UNIT_STRING; isProgressTextShow = true; bgBitmapButton = BitmapFactory.decodeResource(getResources(), R.drawable.ic_wd_curtain_h_open); } private void initPaint() { mImagePaint = new Paint(); offlinePaint = new Paint(); offlinePaint.setColor(HDLUtlisXM.DEFAULT_OFFLINE_COLOR); offlinePaint.setAntiAlias(true);//设置抗锯齿 mProgressPaint = new Paint(); mProgressPaint.setColor(HDLUtlisXM.DEFAULT_OFFLINE_COLOR); mProgressPaint.setAntiAlias(true);//设置抗锯齿 initTextPanit(); } // 初始化拖动按钮顶部文字画笔和进度圆弧画笔 private void initTextPanit() { mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setStrokeWidth(1); mTextPaint.setTextSize(getTextSizeDip(16)); mTextPaint.setColor(Color.BLACK); mTextPaint.setTextAlign(Paint.Align.CENTER); } // private void initAttrs(Context context, AttributeSet attrs) { // TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HDLDiySeekBarSeekBar); // // 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 onDiySeekBarSizeChange() { mDiySeekBarViewWidth = mSeekBarWidth - mPadding * 2; mDiySeekBarPaddingTop = mSeekBarHeight/2 - mDiySeekBarViewHeight/2; mDiySeekBarPaddingBottom = mSeekBarHeight/2 + mDiySeekBarViewHeight/2; updateBitmapImage(); } private void updateBitmapImage(){ try { bgBitmapButton = resizeImage(bgBitmapButton, (int) buttonWidth, (int) buttonWidth); } catch (Exception e) { Log.e("updateBitmapImage 失败", e.getMessage()); } } @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; onDiySeekBarSizeChange(); } 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; onDiySeekBarSizeChange(); // Log.i("getCurrentProgress ","mSeekBarHeight :Y " + mSeekBarHeight + " mSeekBarWidth:"+mSeekBarWidth); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); nowX = (mPercent) * mDiySeekBarViewWidth + mPadding; int round = mDiySeekBarViewHeight / 2; //设置progress内部是灰色 mProgressPaint.setColor(mBackgroundColor); RectF rectBlackBg = new RectF(mPadding, mDiySeekBarPaddingTop , mSeekBarWidth - mPadding, mDiySeekBarPaddingBottom); canvas.drawRoundRect(rectBlackBg, round, round, mProgressPaint); //设置进度条进度及颜色 RectF rectProgressBg = new RectF(mPadding, mDiySeekBarPaddingTop , nowX, mDiySeekBarPaddingBottom ); if (mPercent != 0.0f) { mProgressPaint.setColor(mProgressBarColor); } else { mProgressPaint.setColor(Color.TRANSPARENT); } canvas.drawRoundRect(rectProgressBg, round, round, mProgressPaint); canvas.drawBitmap(bgBitmapButton, nowX - bgBitmapButton.getWidth()/2.0F, mCenterY- bgBitmapButton.getHeight()/2.0F, mImagePaint); if (isProgressTextShow) { canvas.drawText(String.valueOf(getProgress()) + mProgressBarUnitSring, nowX, mDiySeekBarPaddingTop - 30, mTextPaint); } //绘制离线遮挡层 if(isOffline){ RectF rectF2 = new RectF(0, 0, mSeekBarWidth, mSeekBarHeight); canvas.drawRoundRect(rectF2, offlineRadius, offlineRadius, offlinePaint); } canvas.restore(); } public Bitmap getBitmap(int resId) { BitmapFactory.Options options = new BitmapFactory.Options(); TypedValue value = new TypedValue(); getResources().openRawResource(resId, value); options.inTargetDensity = value.density; options.inScaled = false;//不缩放 return BitmapFactory.decodeResource(getResources(), resId, options); } public Bitmap resizeImage(Bitmap bitmap, int width, int height) { int bmpWidth = bitmap.getWidth(); int bmpHeight = bitmap.getHeight(); float scaleWidth = ((float) width) / bmpWidth; float scaleHeight = ((float) height) / bmpHeight; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); return Bitmap.createBitmap(bitmap, 0, 0, bmpWidth, bmpHeight, matrix, true); } //--- 初始化结束 ------------------------------------------------------------------------------- //--- 状态存储 --------------------------------------------------------------------------------- private static final String KEY_PROGRESS_PRESENT = "PRESENTHC"; // 用于存储和获取当前百分比 @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 boolean mCanDrag = false; // 是否允许拖动 // private boolean bDownLeft = 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) { float progressX = event.getX() - mPadding; float progress = progressX /mDiySeekBarViewWidth; if (progress < 0) progress = 0; if (progress > 1) progress = 1; mPercent = progress; mProgress = (int) ((mPercent) * (mMaxValue - mMinValue)) + mMinValue; } private boolean isInArcProgress(float px, float py) { if (px < 0 || px > mSeekBarWidth || py < 0 || py > mSeekBarHeight) { return false; } else { return true; } } // endregion ----------------------------------------------------------------------------------- // region 状态回调 ------------------------------------------------------------------------------ private HDLDiyImageSeekBar.OnProgressChangeListener mOnProgressChangeListener; public void setOnProgressChangeListener(HDLDiyImageSeekBar.OnProgressChangeListener onProgressChangeListener) { mOnProgressChangeListener = onProgressChangeListener; } public interface OnProgressChangeListener { /** * 进度发生变化 * * @param seekBar 拖动条 * @param progress 当前进度数值 * @param isUser 是否是用户操作, true 表示用户拖动, false 表示通过代码设置 */ void onProgressChanged(HDLDiyImageSeekBar seekBar, int progress, boolean isUser); /** * 用户开始拖动 * * @param seekBar 拖动条 */ void onStartTrackingTouch(HDLDiyImageSeekBar seekBar); /** * 用户结束拖动 * * @param seekBar 拖动条 */ void onStopTrackingTouch(HDLDiyImageSeekBar 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 setDiySeekBarPadding(int mmPadding) { mPadding = mmPadding; onDiySeekBarSizeChange(); } public void setProgressTextShow(boolean progressTextShow) { isProgressTextShow = progressTextShow; } public void setDiySeekBarViewHeight(int diySeekBarViewHeight) { mDiySeekBarViewHeight = diySeekBarViewHeight; onDiySeekBarSizeChange(); } public void setBitmapButtonHeight(int mHeight) { this.buttonWidth = mHeight; updateBitmapImage(); } public void setProgressBarColor(int progressBarColor) { mProgressBarColor = progressBarColor; } public void setBarBackgroundColor(int backgroundColor) { mBackgroundColor = backgroundColor; } public void setBgBitmapButton(Bitmap bgBitmapButton) { this.bgBitmapButton = bgBitmapButton; updateBitmapImage(); } /** * 设置离线状态 * @param offline */ public void setOffline(boolean offline) { isOffline = offline; isClickable = !isOffline; postInvalidate(); } }