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();
|
}
|
}
|