package com.hdl.widget;
|
|
import android.annotation.SuppressLint;
|
import android.content.Context;
|
import android.content.res.TypedArray;
|
import android.graphics.Canvas;
|
import android.graphics.Color;
|
import android.graphics.Matrix;
|
import android.graphics.Paint;
|
import android.graphics.Path;
|
import android.graphics.PathMeasure;
|
import android.graphics.Point;
|
import android.graphics.RectF;
|
import android.graphics.Region;
|
import android.graphics.SweepGradient;
|
import android.os.Bundle;
|
import android.os.Parcelable;
|
import android.util.AttributeSet;
|
import android.util.Log;
|
import android.util.TypedValue;
|
import android.view.GestureDetector;
|
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;
|
|
|
public class HDLArcSeekBar extends View {
|
private static final int DEFAULT_EDGE_LENGTH = 260; // 默认宽高
|
|
private static final float CIRCLE_ANGLE = 360; // 圆周角
|
private static final int DEFAULT_ARC_WIDTH = 15; // 默认宽度 dp
|
private static final float DEFAULT_OPEN_ANGLE = 30; // 开口角度
|
private static final float DEFAULT_ROTATE_ANGLE = 90; // 旋转角度
|
private static final int DEFAULT_BORDER_WIDTH = 0; // 默认描边宽度
|
private static final int DEFAULT_BORDER_COLOR = 0xffffffff; // 默认描边颜色
|
|
private static final int DEFAULT_THUMB_COLOR = 0xffffffff; // 拖动按钮颜色
|
private static final int DEFAULT_THUMB_WIDTH = 5; // 拖动按钮描边宽度 dp
|
private static final int DEFAULT_THUMB_RADIUS = 7; // 拖动按钮半径 dp
|
private static final int DEFAULT_THUMB_SHADOW_RADIUS = 0; // 拖动按钮阴影半径 dp
|
private static final int DEFAULT_THUMB_SHADOW_COLOR = 0xFF000000; // 拖动按钮阴影颜色
|
|
private static final int DEFAULT_SHADOW_RADIUS = 0; // 默认阴影半径 dp
|
public static final int THUMB_MODE_STROKE = 0; // 拖动按钮模式 - 描边
|
public static final int THUMB_MODE_FILL = 1; // 拖动按钮模式 - 填充
|
public static final int THUMB_MODE_FILL_STROKE = 2; // 拖动按钮模式 - 填充+描边
|
private static final int DEFAULT_MAX_VALUE = 100; // 默认最大数值
|
private static final int DEFAULT_MIN_VALUE = 0; // 默认最小数值
|
private static final String KEY_PROGRESS_PRESENT = "PRESENT"; // 用于存储和获取当前百分比
|
|
// 可配置数据
|
private int[] mArcColors; // Seek 颜色
|
private float mArcWidth; // Seek 宽度
|
private float mOpenAngle; // 开口的角度大小 0 - 360
|
private float mRotateAngle; // 旋转角度
|
private int mBorderWidth; // 描边宽度
|
private int mBorderColor; // 描边颜色
|
private int mThumbColor; // 拖动按钮颜色
|
private float mThumbWidth; // 拖动按钮宽度
|
private float mThumbRadius; // 拖动按钮半径
|
private float mThumbShadowRadius;// 拖动按钮阴影半径
|
private int mThumbShadowColor;// 拖动按钮阴影颜色
|
private int mThumbMode; // 拖动按钮模式
|
|
private int mShadowRadius; // 阴影半径
|
|
private int mMaxValue; // 最大数值
|
private int mMinValue; // 最小数值
|
|
private float mCenterX; // 圆弧 SeekBar 中心点 X
|
private float mCenterY; // 圆弧 SeekBar 中心点 Y
|
|
private float mThumbX; // 拖动按钮 中心点 X
|
private float mThumbY; // 拖动按钮 中心点 Y
|
|
private Path mSeekPath;
|
private Path mBorderPath;
|
private Paint mArcPaint;
|
private Paint mThumbPaint;
|
private Paint mBorderPaint;
|
private Paint mShadowPaint;
|
|
private float[] mTempPos;
|
private float[] mTempTan;
|
private PathMeasure mSeekPathMeasure;
|
|
private float mProgressPresent = 0; // 当前进度百分比
|
private boolean mCanDrag = false; // 是否允许拖动
|
private boolean mAllowTouchSkip = false; // 是否允许越过边界
|
// private GestureDetector mDetector;
|
private Matrix mInvertMatrix; // 逆向 Matrix, 用于计算触摸坐标和绘制坐标的转换
|
private Region mArcRegion; // ArcPath的实际区域大小,用于判定单击事件
|
|
//***********************新增***********************************
|
private static final int DEFAULT_THUMB_DISTANCE_MULTIPLE = 5; //点击的坐标离与mThumb圆心坐标距离,小于5*半径,则可以拖动
|
private static final int DEFAULT_ARC_PROGRESS_BAR_COLOR = 0xFFFFFFFF; // 进度条颜色
|
private static final String DEFAULT_ARC_PROGRESS_BAR_UNIT_STRING = "%"; // 默认显示单位
|
// private static final int DEFAULT_DISTANCE_BETWEEN_TEXTPOINT_AND_ARC = 70;
|
private static final int DEFAULT_PADDING = 80; //圆弧自带PADDING值,为了显示进度test文字
|
private Point mTextPoint; //旋转90度后的坐标
|
private Paint mTextPaint; //进度文字显示内容
|
private RectF content; //显示内容区域
|
private float mSweepAngle = 0; //与开始角度的夹角
|
private int mArcProgressBarColor; //当前进度圆弧颜色
|
private Paint mArcProgressBarPaint; //当前进度圆弧画笔
|
private String mProgressBarUnitSring; //进度单位符号
|
private double mArcProgressBarRadius; //圆弧的半径
|
private boolean isClickable = true;
|
private int mTextDefaultDistance = 70; // 进度显示文字坐标与进度圆弧的距离 DEFAULT_DISTANCE_BETWEEN_TEXTPOINT_AND_ARC
|
private int[] mArcProgressBarColors; // 当前进度圆弧渐变颜色数组
|
// private int mTextColor; // 拖动按钮颜色
|
//***********************新增***********************************
|
|
|
public HDLArcSeekBar(Context context) {
|
this(context, null);
|
}
|
|
public HDLArcSeekBar(Context context, AttributeSet attrs) {
|
this(context, attrs, 0);
|
}
|
|
public HDLArcSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
|
super(context, attrs, defStyleAttr);
|
setSaveEnabled(true);
|
setLayerType(LAYER_TYPE_SOFTWARE, null);
|
initAttrs(context, attrs);
|
initData();
|
initPaint();
|
}
|
|
//--- 初始化 -----------------------------------------------------------------------------------
|
|
// 初始化各种属性
|
private void initAttrs(Context context, AttributeSet attrs) {
|
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.HDLArcSeekBar);
|
mArcColors = getArcColors(context, ta);
|
mArcWidth = ta.getDimensionPixelSize(R.styleable.HDLArcSeekBar_arc_width, dp2px(DEFAULT_ARC_WIDTH));
|
mOpenAngle = ta.getFloat(R.styleable.HDLArcSeekBar_arc_open_angle, DEFAULT_OPEN_ANGLE);
|
mRotateAngle = ta.getFloat(R.styleable.HDLArcSeekBar_arc_rotate_angle, DEFAULT_ROTATE_ANGLE);
|
mMaxValue = ta.getInt(R.styleable.HDLArcSeekBar_arc_max, DEFAULT_MAX_VALUE);
|
mMinValue = ta.getInt(R.styleable.HDLArcSeekBar_arc_min, DEFAULT_MIN_VALUE);
|
// 如果用户设置的最大值和最小值不合理,则直接按照默认进行处理
|
if (mMaxValue <= mMinValue) {
|
mMaxValue = DEFAULT_MAX_VALUE;
|
mMinValue = DEFAULT_MIN_VALUE;
|
}
|
int progress = ta.getInt(R.styleable.HDLArcSeekBar_arc_progress, mMinValue);
|
setProgress(progress);
|
mBorderWidth = ta.getDimensionPixelSize(R.styleable.HDLArcSeekBar_arc_border_width, dp2px(DEFAULT_BORDER_WIDTH));
|
mBorderColor = ta.getColor(R.styleable.HDLArcSeekBar_arc_border_color, DEFAULT_BORDER_COLOR);
|
|
mThumbColor = ta.getColor(R.styleable.HDLArcSeekBar_arc_thumb_color, DEFAULT_THUMB_COLOR);
|
mThumbRadius = ta.getDimensionPixelSize(R.styleable.HDLArcSeekBar_arc_thumb_radius, dp2px(DEFAULT_THUMB_RADIUS));
|
mThumbShadowRadius = ta.getDimensionPixelSize(R.styleable.HDLArcSeekBar_arc_thumb_shadow_radius, dp2px(DEFAULT_THUMB_SHADOW_RADIUS));
|
mThumbShadowColor = ta.getColor(R.styleable.HDLArcSeekBar_arc_thumb_shadow_color, DEFAULT_THUMB_SHADOW_COLOR);
|
mThumbWidth = ta.getDimensionPixelSize(R.styleable.HDLArcSeekBar_arc_thumb_width, dp2px(DEFAULT_THUMB_WIDTH));
|
mThumbMode = ta.getInt(R.styleable.HDLArcSeekBar_hdl_arc_thumb_mode, THUMB_MODE_STROKE);
|
|
mShadowRadius = ta.getDimensionPixelSize(R.styleable.HDLArcSeekBar_arc_shadow_radius, dp2px(DEFAULT_SHADOW_RADIUS));
|
mArcProgressBarColor = ta.getColor(R.styleable.HDLArcSeekBar_arc_progress_bar_color, DEFAULT_ARC_PROGRESS_BAR_COLOR);
|
|
mArcProgressBarColors = new int[]{mArcProgressBarColor,mArcProgressBarColor};
|
|
ta.recycle();
|
}
|
|
// 获取 Arc 颜色数组
|
private int[] getArcColors(Context context, TypedArray ta) {
|
int[] ret;
|
int resId = ta.getResourceId(R.styleable.HDLArcSeekBar_arc_colors, 0);
|
if (0 == resId) {
|
resId = R.array.arc_colors_default;
|
}
|
ret = getColorsByArrayResId(context, resId);
|
return ret;
|
}
|
|
// 根据 resId 获取颜色数组
|
private int[] getColorsByArrayResId(Context context, int resId) {
|
int[] ret;
|
TypedArray colorArray = context.getResources().obtainTypedArray(resId);
|
ret = new int[colorArray.length()];
|
for (int i = 0; i < colorArray.length(); i++) {
|
ret[i] = colorArray.getColor(i, 0);
|
}
|
return ret;
|
}
|
|
// 初始化数据
|
private void initData() {
|
mSeekPath = new Path();
|
mBorderPath = new Path();
|
mSeekPathMeasure = new PathMeasure();
|
mTempPos = new float[2];
|
mTempTan = new float[2];
|
|
// mDetector = new GestureDetector(getContext(), new OnClickListener());
|
mInvertMatrix = new Matrix();
|
mArcRegion = new Region();
|
mProgressBarUnitSring = DEFAULT_ARC_PROGRESS_BAR_UNIT_STRING;
|
}
|
|
// 初始化画笔
|
private void initPaint() {
|
initArcPaint();
|
initThumbPaint();
|
initTextPanit();
|
initProgressBarPaint();
|
initBorderPaint();
|
initShadowPaint();
|
}
|
|
|
// 初始化圆弧画笔
|
private void initArcPaint() {
|
mArcPaint = new Paint();
|
mArcPaint.setAntiAlias(true);
|
mArcPaint.setStrokeWidth(mArcWidth);
|
mArcPaint.setStyle(Paint.Style.STROKE);
|
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
|
}
|
|
// 初始化拖动按钮画笔
|
private void initThumbPaint() {
|
mThumbPaint = new Paint();
|
mThumbPaint.setAntiAlias(true);
|
mThumbPaint.setColor(mThumbColor);
|
mThumbPaint.setStrokeWidth(mThumbWidth);
|
mThumbPaint.setStrokeCap(Paint.Cap.ROUND);
|
if (mThumbMode == THUMB_MODE_FILL) {
|
mThumbPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
} else if (mThumbMode == THUMB_MODE_FILL_STROKE) {
|
mThumbPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
} else {
|
mThumbPaint.setStyle(Paint.Style.STROKE);
|
}
|
mThumbPaint.setTextSize(56);
|
}
|
|
private float getTextSizeDip(float value) {
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
|
}
|
|
// 初始化进度圆弧画笔
|
private void initProgressBarPaint() {
|
mArcProgressBarPaint = new Paint(); //初始化进度圆弧画笔
|
mArcProgressBarPaint.setAntiAlias(true);
|
mArcProgressBarPaint.setStyle(Paint.Style.STROKE);
|
mArcProgressBarPaint.setStrokeCap(Paint.Cap.ROUND);
|
mArcProgressBarPaint.setStrokeWidth(mArcWidth - 1);
|
// mArcProgressBarPaint.setColor(mArcProgressBarColor);
|
|
|
}
|
|
// 初始化拖动按钮顶部文字画笔和进度圆弧画笔
|
private void initTextPanit() {
|
mTextPaint = new Paint();
|
mTextPaint.setAntiAlias(true);
|
mTextPaint.setStrokeWidth(1);
|
mTextPaint.setTextSize(getTextSizeDip(12));
|
mTextPaint.setColor(mThumbColor);
|
mTextPaint.setTextAlign(Paint.Align.CENTER);
|
}
|
|
// 初始化拖动按钮画笔
|
private void initBorderPaint() {
|
mBorderPaint = new Paint();
|
mBorderPaint.setAntiAlias(true);
|
mBorderPaint.setColor(mBorderColor);
|
mBorderPaint.setStrokeWidth(mBorderWidth);
|
mBorderPaint.setStyle(Paint.Style.STROKE);
|
}
|
|
// 初始化阴影画笔
|
private void initShadowPaint() {
|
mShadowPaint = new Paint();
|
mShadowPaint.setAntiAlias(true);
|
mShadowPaint.setStrokeWidth(mBorderWidth);
|
mShadowPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
}
|
|
//--- 初始化结束 -------------------------------------------------------------------------------
|
|
//--- 状态存储 ---------------------------------------------------------------------------------
|
|
@Override
|
protected Parcelable onSaveInstanceState() {
|
Bundle bundle = new Bundle();
|
bundle.putParcelable("superState", super.onSaveInstanceState());
|
bundle.putFloat(KEY_PROGRESS_PRESENT, mProgressPresent);
|
return bundle;
|
}
|
|
@Override
|
protected void onRestoreInstanceState(Parcelable state) {
|
if (state instanceof Bundle) {
|
Bundle bundle = (Bundle) state;
|
this.mProgressPresent = bundle.getFloat(KEY_PROGRESS_PRESENT);
|
state = bundle.getParcelable("superState");
|
}
|
if (null != mOnProgressChangeListener) {
|
mOnProgressChangeListener.onProgressChanged(this, getProgress(), false);
|
}
|
super.onRestoreInstanceState(state);
|
}
|
|
//--- 状态存储结束 -----------------------------------------------------------------------------
|
|
@Override
|
protected void onMeasure(int widthMeasureSpec, int 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));
|
}
|
|
@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();
|
float edgeLength, startX, startY;
|
float fix = mArcWidth / 2 + mBorderWidth + mShadowRadius * 2; // 修正距离,画笔宽度的修正
|
if (safeW < safeH) {
|
// 宽度小于高度,以宽度为准
|
edgeLength = safeW - fix;
|
startX = getPaddingLeft();
|
startY = (safeH - safeW) / 2.0f + getPaddingTop();
|
} else {
|
// 宽度大于高度,以高度为准
|
edgeLength = safeH - fix;
|
startX = (safeW - safeH) / 2.0f + getPaddingLeft();
|
startY = getPaddingTop();
|
}
|
|
// 得到显示区域和中心的
|
content = new RectF(startX + fix + DEFAULT_PADDING, startY + fix + DEFAULT_PADDING, startX + edgeLength - DEFAULT_PADDING, startY + edgeLength - DEFAULT_PADDING);
|
mCenterX = content.centerX();
|
mCenterY = content.centerY();
|
|
// 得到路径
|
mSeekPath.reset();
|
mSeekPath.addArc(content, mOpenAngle / 2, CIRCLE_ANGLE - mOpenAngle);
|
mSeekPathMeasure.setPath(mSeekPath, false);
|
computeThumbPos(mProgressPresent);
|
mArcProgressBarRadius = getDistanceWithCenter(mThumbX, mThumbY);//计算出圆弧的半径
|
resetShaderColor();
|
mInvertMatrix.reset();
|
mInvertMatrix.preRotate(-mRotateAngle, mCenterX, mCenterY);
|
|
mArcPaint.getFillPath(mSeekPath, mBorderPath);
|
mBorderPath.close();
|
mArcRegion.setPath(mBorderPath, new Region(0, 0, w, h));
|
}
|
|
|
|
/**
|
* 重置 mArcProgressBarColors 颜色
|
* 2019-8-14
|
*/
|
private void resetmArcProgressBarColor() {
|
// // 计算渐变数组
|
// float startPos = (mOpenAngle / 2) / CIRCLE_ANGLE;
|
// float stopPos = (CIRCLE_ANGLE - (mOpenAngle / 2)) / CIRCLE_ANGLE;
|
// int len = mArcProgressBarColors.length - 1;
|
// float distance = (stopPos - startPos) / len;
|
// float pos[] = new float[mArcProgressBarColors.length];
|
// for (int i = 0; i < mArcProgressBarColors.length; i++) {
|
// pos[i] = startPos + (distance * i);
|
// }
|
// SweepGradient gradient = new SweepGradient(mCenterX, mCenterY, mArcProgressBarColors, pos);
|
|
SweepGradient gradient = new SweepGradient(mCenterX, mCenterY, mArcProgressBarColors, null);
|
|
|
mArcProgressBarPaint.setShader(gradient);
|
}
|
|
// 重置 shader 颜色
|
private void resetShaderColor() {
|
// 计算渐变数组
|
float startPos = (mOpenAngle / 2) / CIRCLE_ANGLE;
|
float stopPos = (CIRCLE_ANGLE - (mOpenAngle / 2)) / CIRCLE_ANGLE;
|
int len = mArcColors.length - 1;
|
float distance = (stopPos - startPos) / len;
|
float pos[] = new float[mArcColors.length];
|
for (int i = 0; i < mArcColors.length; i++) {
|
pos[i] = startPos + (distance * i);
|
}
|
SweepGradient gradient = new SweepGradient(mCenterX, mCenterY, mArcColors, pos);
|
mArcPaint.setShader(gradient);
|
}
|
|
// 具体绘制
|
@Override
|
protected void onDraw(Canvas canvas) {
|
canvas.save();
|
canvas.drawText(String.valueOf(getProgress()) + mProgressBarUnitSring, mTextPoint.x, mTextPoint.y, mTextPaint);
|
canvas.rotate(mRotateAngle, mCenterX, mCenterY);
|
// mShadowPaint.setShadowLayer(mShadowRadius * 2, 0, 0, getColor());
|
canvas.drawPath(mBorderPath, mShadowPaint);
|
canvas.drawPath(mSeekPath, mArcPaint);
|
//当前进度
|
resetmArcProgressBarColor();//渐变颜色
|
canvas.drawArc(content, mOpenAngle / 2, mSweepAngle, false, mArcProgressBarPaint);
|
if (mBorderWidth > 0) {
|
canvas.drawPath(mBorderPath, mBorderPaint);
|
}
|
if (mThumbShadowRadius > 0) {
|
mThumbPaint.setShadowLayer(mThumbShadowRadius, 0, 0, mThumbShadowColor);
|
canvas.drawCircle(mThumbX, mThumbY, mThumbRadius, mThumbPaint);
|
mThumbPaint.clearShadowLayer();
|
}
|
canvas.drawCircle(mThumbX, mThumbY, mThumbRadius, mThumbPaint);
|
canvas.restore();
|
}
|
|
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;
|
}
|
float tempProgressPresent = getCurrentProgress(event.getX(), event.getY());
|
if (!mAllowTouchSkip) {
|
// 不允许突变
|
if (Math.abs(tempProgressPresent - mProgressPresent) > 0.5f) {
|
break;
|
}
|
}
|
// 允许突变 或者非突变
|
mProgressPresent = tempProgressPresent;
|
computeThumbPos(mProgressPresent);
|
// 事件回调
|
if (null != mOnProgressChangeListener && getProgress() != lastProgress) {
|
mOnProgressChangeListener.onProgressChanged(this, getProgress(), true);
|
lastProgress = getProgress();
|
}
|
moved = true;
|
break;
|
case ACTION_UP:
|
case ACTION_CANCEL:
|
if(!moved){
|
if (isInArcProgress(event.getX(), event.getY())) {
|
// 点击允许突变
|
mProgressPresent = getCurrentProgress(event.getX(), event.getY());
|
computeThumbPos(mProgressPresent);
|
}
|
}
|
if (null != mOnProgressChangeListener) {
|
mOnProgressChangeListener.onStopTrackingTouch(this);
|
}
|
|
break;
|
}
|
// mDetector.onTouchEvent(event);
|
invalidate();
|
return true;
|
}
|
|
// 判断是否允许拖动
|
private void judgeCanDrag(MotionEvent event) {
|
float[] pos = {event.getX(), event.getY()};
|
mInvertMatrix.mapPoints(pos);
|
if (getDistance(pos[0], pos[1]) <= mThumbRadius * DEFAULT_THUMB_DISTANCE_MULTIPLE) {
|
mCanDrag = true;
|
} else {
|
mCanDrag = false;
|
}
|
}
|
|
|
private class OnClickListener extends GestureDetector.SimpleOnGestureListener {
|
@Override
|
public boolean onSingleTapUp(MotionEvent e) {
|
// 判断是否点击在了进度区域
|
if (!isInArcProgress(e.getX(), e.getY())) {
|
return false;
|
}
|
// 点击允许突变
|
mProgressPresent = getCurrentProgress(e.getX(), e.getY());
|
computeThumbPos(mProgressPresent);
|
|
Log.i("onSingleTapUp","onSingleTapUp");
|
// // 事件回调
|
// if (null != mOnProgressChangeListener) {
|
// mOnProgressChangeListener.onProgressChanged(HDLArcSeekBar.this, getProgress(), true);
|
//// mOnProgressChangeListener.onStopTrackingTouch(HDLArcSeekBar.this);
|
// }
|
return true;
|
}
|
}
|
|
// // 判断该点是否在进度条上面
|
// private boolean isInArcProgress(float px, float py) {
|
// float[] pos = {px, py};
|
// mInvertMatrix.mapPoints(pos);
|
// return mArcRegion.contains((int) pos[0], (int) pos[1]);
|
// }
|
|
/**
|
* 判断该点是否在进度条附近 2019-07-17
|
* 对比判断该点是否在进度条上面,增大可点击区域
|
*
|
* @param px 当前坐标x
|
* @param py 当前坐标y
|
* @return
|
*/
|
private boolean isInArcProgress(float px, float py) {
|
float[] pos = {px, py};
|
mInvertMatrix.mapPoints(pos);
|
double mDistance = getDistanceWithCenter(pos[0], pos[1]);
|
// Log.i("kkk" ,"KmArcProgressBarRadiusmDistance"+mDistance);
|
if ((mDistance >= (mArcProgressBarRadius * 2 / 3))
|
&& (mDistance <= (mArcProgressBarRadius * 4 / 3))) {
|
return true;
|
} else {
|
return false;
|
}
|
}
|
|
// 获取当前进度理论进度数值
|
private float getCurrentProgress(float px, float py) {
|
float diffAngle = getDiffAngle(px, py);
|
float progress = diffAngle / (CIRCLE_ANGLE - mOpenAngle);
|
if (progress < 0) progress = 0;
|
if (progress > 1) progress = 1;
|
return progress;
|
}
|
|
// 获得当前点击位置所成角度与开始角度之间的数值差
|
private float getDiffAngle(float px, float py) {
|
float angle = getAngle(px, py);
|
float diffAngle;
|
diffAngle = angle - mRotateAngle;
|
if (diffAngle < 0) {
|
diffAngle = (diffAngle + CIRCLE_ANGLE) % CIRCLE_ANGLE;
|
}
|
diffAngle = diffAngle - mOpenAngle / 2;
|
return diffAngle;
|
}
|
|
// 计算指定位置与内容区域中心点的夹角
|
private float getAngle(float px, float py) {
|
float angle = (float) ((Math.atan2(py - mCenterY, px - mCenterX)) * 180 / 3.14f);
|
if (angle < 0) {
|
angle += 360;
|
}
|
return angle;
|
}
|
|
// 计算指定位置与上次位置的距离
|
private float getDistance(float px, float py) {
|
return (float) Math.sqrt((px - mThumbX) * (px - mThumbX) + (py - mThumbY) * (py - mThumbY));
|
}
|
|
// 计算坐标圆点的距离
|
private double getDistanceWithCenter(float px, float py) {
|
return Math.sqrt((px - mCenterX) * (px - mCenterX) + (py - mCenterY) * (py - mCenterY));
|
}
|
|
private int dp2px(int dp) {
|
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
|
}
|
|
/**
|
* 获取相同距离下,圆弧对应的第三点坐标
|
*
|
* @param mPoint 圆弧坐标
|
* 第三点距离第二点的距离
|
* DEFAULT_DISTANCE_BETWEEN_TEXTPOINT_AND_ARC 距离
|
*/
|
private Point calcOutsidePoint(Point mPoint) {
|
double newX = (mPoint.x * (mArcProgressBarRadius + mTextDefaultDistance) - mCenterX * mTextDefaultDistance) / mArcProgressBarRadius;
|
double newY = (mPoint.y * (mArcProgressBarRadius + mTextDefaultDistance) - mCenterY * mTextDefaultDistance) / mArcProgressBarRadius;
|
return new Point((int) newX, (int) newY);
|
}
|
|
|
// 计算拖动块应该显示的位置
|
private void computeThumbPos(float present) {
|
if (present < 0) present = 0;
|
if (present > 1) present = 1;
|
if (null == mSeekPathMeasure) return;
|
float distance = mSeekPathMeasure.getLength() * present;
|
mSeekPathMeasure.getPosTan(distance, mTempPos, mTempTan);
|
mThumbX = mTempPos[0];
|
mThumbY = mTempPos[1];
|
Point mmTextPoint = calcNewPoint(new Point((int) mThumbX, (int) mThumbY), new Point((int) mCenterX, (int) mCenterY), mRotateAngle);
|
mSweepAngle = getDiffAngle(mmTextPoint.x, mmTextPoint.y);
|
if (mSweepAngle < 0) mSweepAngle = 0;
|
// Log.i("mSweepAngle", "mSweepAngle:" + mSweepAngle);
|
|
mTextPoint = calcOutsidePoint(mmTextPoint);
|
}
|
|
//--- 线性取色 ---------------------------------------------------------------------------------
|
|
/**
|
* 获取当前进度的具体颜色
|
*
|
* @return 当前进度在渐变中的颜色
|
*/
|
public int getColor() {
|
return getColor(mProgressPresent);
|
}
|
|
/**
|
* 获取某个百分比位置的颜色
|
*
|
* @param radio 取值[0,1]
|
* @return 最终颜色
|
*/
|
private int getColor(float radio) {
|
float diatance = 1.0f / (mArcColors.length - 1);
|
int startColor;
|
int endColor;
|
if (radio >= 1) {
|
return mArcColors[mArcColors.length - 1];
|
}
|
for (int i = 0; i < mArcColors.length; i++) {
|
if (radio <= i * diatance) {
|
if (i == 0) {
|
return mArcColors[0];
|
}
|
startColor = mArcColors[i - 1];
|
endColor = mArcColors[i];
|
float areaRadio = getAreaRadio(radio, diatance * (i - 1), diatance * i);
|
return getColorFrom(startColor, endColor, areaRadio);
|
}
|
}
|
return -1;
|
}
|
|
/**
|
* 计算当前比例在子区间的比例
|
*
|
* @param radio 总比例
|
* @param startPosition 子区间开始位置
|
* @param endPosition 子区间结束位置
|
* @return 自区间比例[0, 1]
|
*/
|
private float getAreaRadio(float radio, float startPosition, float endPosition) {
|
return (radio - startPosition) / (endPosition - startPosition);
|
}
|
|
/**
|
* 取两个颜色间的渐变区间 中的某一点的颜色
|
*
|
* @param startColor 开始的颜色
|
* @param endColor 结束的颜色
|
* @param radio 比例 [0, 1]
|
* @return 选中点的颜色
|
*/
|
private int getColorFrom(int startColor, int endColor, float radio) {
|
int redStart = Color.red(startColor);
|
int blueStart = Color.blue(startColor);
|
int greenStart = Color.green(startColor);
|
int redEnd = Color.red(endColor);
|
int blueEnd = Color.blue(endColor);
|
int greenEnd = Color.green(endColor);
|
|
int red = (int) (redStart + ((redEnd - redStart) * radio + 0.5));
|
int greed = (int) (greenStart + ((greenEnd - greenStart) * radio + 0.5));
|
int blue = (int) (blueStart + ((blueEnd - blueStart) * radio + 0.5));
|
return Color.argb(255, red, greed, blue);
|
}
|
|
|
/**
|
* 计算某点绕中心点旋转一个角度后的坐标
|
*
|
* @param pCenter 中心坐标
|
*/
|
private static Point calcNewPoint(Point p, Point pCenter, float angle) {
|
// calc arc
|
float l = (float) ((angle * Math.PI) / 180);
|
|
//sin/cos value
|
float cosv = (float) Math.cos(l);
|
float sinv = (float) Math.sin(l);
|
|
// calc new point
|
float newX = (float) ((p.x - pCenter.x) * cosv - (p.y - pCenter.y) * sinv + pCenter.x);
|
float newY = (float) ((p.x - pCenter.x) * sinv + (p.y - pCenter.y) * cosv + pCenter.y);
|
return new Point((int) newX, (int) newY);
|
}
|
|
// /**
|
// * 求第三点坐标
|
// *
|
// * @param pCenter 中心坐标
|
// * @param distance 第三点距离第二点的距离
|
// */
|
// private static Point calcOutsidePoint(Point p, Point pCenter, double distance) {
|
// //计算2点之间的距离
|
// double ll = Math.sqrt((p.x - pCenter.x) * (p.x - pCenter.x) + (p.y - pCenter.y) * (p.y - pCenter.y));
|
//
|
// // calc new point
|
// double newX = (p.x * (ll + distance) - pCenter.x * distance) / ll;
|
// double newY = (p.y * (ll + distance) - pCenter.y * distance) / ll;
|
// return new Point((int) newX, (int) newY);
|
// }
|
//
|
|
|
//****************************对外接口****************************************************
|
/**
|
* 设置控件是否可用点击
|
* @param isClickable
|
*/
|
public void setIsClickable(boolean isClickable) {
|
this.isClickable = isClickable;
|
}
|
|
/**
|
* 设置进度
|
*
|
* @param progress 进度值
|
*/
|
public void setProgress(int progress) {
|
System.out.println("setProgress = " + progress);
|
if (progress > mMaxValue) progress = mMaxValue;
|
if (progress < mMinValue) progress = mMinValue;
|
mProgressPresent = (progress - mMinValue) * 1.0f / (mMaxValue - mMinValue);
|
// System.out.println("setProgress present = " + mProgressPresent);
|
// if (null != mOnProgressChangeListener) {
|
// mOnProgressChangeListener.onProgressChanged(this, progress, false);
|
// }
|
computeThumbPos(mProgressPresent);
|
postInvalidate();
|
}
|
|
/**
|
* 获取当前进度数值
|
*
|
* @return 当前进度数值
|
*/
|
public int getProgress() {
|
return (int) (mProgressPresent * (mMaxValue - mMinValue)) + mMinValue;
|
}
|
|
/**
|
* 设置颜色
|
* 3个颜色 渐变效果
|
* @param colors 颜色
|
*/
|
public void setProgressBarColors(int[] colors) {
|
if(colors.length < 2) return;
|
mArcProgressBarColors = colors;
|
resetmArcProgressBarColor();
|
postInvalidate();
|
}
|
|
/**
|
* 设置颜色 单种颜色
|
* 2019-8-15
|
* @param colors 颜色
|
*/
|
public void setProgressBarColor(int colors) {
|
int[] colorsArray = new int[]{colors, colors};
|
mArcProgressBarColors = colorsArray;
|
resetmArcProgressBarColor();
|
postInvalidate();
|
}
|
|
/**
|
* 设置颜色 2个颜色以上
|
* 2019-8-15
|
* @param colors 颜色
|
*/
|
public void setArcColors(int[] colors) {
|
if(colors.length < 2) return;
|
mArcColors = colors;
|
resetShaderColor();
|
postInvalidate();
|
}
|
|
/**
|
* 设置颜色
|
* 单种颜色
|
* @param colors 颜色
|
*/
|
public void setArcColor(int colors) {
|
int[] colorsArray = new int[]{colors, colors, colors};
|
mArcColors = colorsArray;
|
resetShaderColor();
|
postInvalidate();
|
}
|
|
/**
|
* 设置最大数值
|
*
|
* @param max 最大数值
|
*/
|
public void setMaxValue(int max) {
|
mMaxValue = max;
|
}
|
|
/**
|
* 设置最小数值
|
*
|
* @param min 最小数值
|
*/
|
public void setMinValue(int min) {
|
mMinValue = min;
|
}
|
|
// /**
|
// * 设置进度条颜色
|
// *
|
// * @param arcProgressPainColor 进度条颜色
|
// */
|
// public void setProgressBarColor(int arcProgressPainColor) {
|
// mArcProgressBarColor = arcProgressPainColor;
|
// mArcProgressBarPaint.setColor(mArcProgressBarColor);
|
// }
|
|
/**
|
* 设置进度显示值单位
|
*
|
* @param progressBarUnitSring 进度显示值单位
|
*/
|
public void setProgressBarUnitSring(String progressBarUnitSring) {
|
mProgressBarUnitSring = progressBarUnitSring;
|
}
|
|
// /**
|
// * 设置颜色
|
// *
|
// * @param colorArrayRes 颜色资源 R.array.arc_color
|
// */
|
// public void setArcColors(int colorArrayRes) {
|
// setArcColors(getColorsByArrayResId(getContext(), colorArrayRes));
|
// }
|
|
/**
|
* 设置圆弧宽度,同时同步拖到按钮宽度
|
* @param arcWidth
|
*/
|
public void setArcWidthDefaultStyle(int arcWidth) {
|
mArcWidth = dp2px(arcWidth);
|
mThumbRadius = mArcWidth / 3;
|
mThumbWidth = mArcWidth * 2 / 9;
|
|
mArcPaint.setStrokeWidth(mArcWidth);
|
mArcProgressBarPaint.setStrokeWidth(mArcWidth - 1);
|
mThumbPaint.setStrokeWidth(mThumbWidth);
|
}
|
|
/**
|
* 开口角度
|
* @param openAngle
|
*/
|
public void setOpenAngle(float openAngle) {
|
mOpenAngle = openAngle;
|
}
|
|
/**
|
*
|
* @param thumbMode
|
*/
|
public void setThumbMode(int thumbMode) {
|
mThumbMode = thumbMode;
|
if (mThumbMode == THUMB_MODE_FILL) {
|
mThumbPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
} else if (mThumbMode == THUMB_MODE_FILL_STROKE) {
|
mThumbPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
} else {
|
mThumbMode = THUMB_MODE_STROKE;
|
mThumbPaint.setStyle(Paint.Style.STROKE);
|
}
|
}
|
|
/**
|
*
|
* @param arcWidth
|
*/
|
public void setArcWidth(int arcWidth) {
|
mArcWidth = dp2px(arcWidth);
|
mArcPaint.setStrokeWidth(mArcWidth);
|
mArcProgressBarPaint.setStrokeWidth(mArcWidth - 1);
|
}
|
|
/**
|
* 拖动滑块半径
|
* @param thumbRadius
|
*/
|
public void setThumbRadius(int thumbRadius) {
|
mThumbRadius = dp2px(thumbRadius);
|
mThumbWidth = mThumbRadius * 2 / 3;
|
mThumbPaint.setStrokeWidth(mThumbWidth);
|
// initThumbPaint();
|
}
|
|
/**
|
* 拖动滑块颜色
|
* @param thumbColor
|
*/
|
public void setThumbColor(int thumbColor) {
|
mThumbColor = thumbColor;
|
mThumbPaint.setColor(mThumbColor);
|
}
|
|
|
/**
|
* 进度文字大小
|
* @param textSize
|
*/
|
public void setProgressTextSize(int textSize){
|
mTextPaint.setTextSize(getTextSizeDip(textSize));
|
}
|
|
/**
|
* 进度文字颜色
|
* @param textPaintColor
|
*/
|
public void setProgressTextColor(int textPaintColor){
|
mTextPaint.setColor(textPaintColor);
|
}
|
|
/**
|
* 进度文字与圆弧距离
|
* @param textDefaultDistance
|
*/
|
public void setTextDefaultDistance(int textDefaultDistance) {
|
mTextDefaultDistance = dp2px(textDefaultDistance);
|
}
|
|
// endregion -----------------------------------------------------------------------------------
|
// region 状态回调 ------------------------------------------------------------------------------
|
|
private OnProgressChangeListener mOnProgressChangeListener;
|
|
public void setOnProgressChangeListener(OnProgressChangeListener onProgressChangeListener) {
|
mOnProgressChangeListener = onProgressChangeListener;
|
}
|
|
public interface OnProgressChangeListener {
|
/**
|
* 进度发生变化
|
*
|
* @param seekBar 拖动条
|
* @param progress 当前进度数值
|
* @param isUser 是否是用户操作, true 表示用户拖动, false 表示通过代码设置
|
*/
|
void onProgressChanged(HDLArcSeekBar seekBar, int progress, boolean isUser);
|
|
/**
|
* 用户开始拖动
|
*
|
* @param seekBar 拖动条
|
*/
|
void onStartTrackingTouch(HDLArcSeekBar seekBar);
|
|
/**
|
* 用户结束拖动
|
*
|
* @param seekBar 拖动条
|
*/
|
void onStopTrackingTouch(HDLArcSeekBar seekBar);
|
}
|
// endregion -----------------------------------------------------------------------------------
|
}
|