import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class SeekBarWithBubbleView extends View {
private Context mContext;
private Paint mSeekBarBgPaint;
private Paint mBubbleViewPaint;
private Bitmap mBubbleBitmap;
private Bitmap mSeekBarBackground;
private float mMin = 0; // min
private float mMax = 100; // max
private float mNowProgress = mMin;
private int mViewWidth;// 获取到视图宽度
private int mViewHeight;// 视图高度
private int mBubbleWidth; // 气泡宽度
private int mBubbleHeight;// 气泡高度
private float mBubbleViewX; // 气泡的X坐标
private float mBubbleViewY;// 气泡的Y坐标
private boolean mDisabledMode = false;// 是否为亮度自动模式,自动模式不可点击
private float mProgressExtraWidth = 0; //坐标预留
private OnProgressChangedListener mProgressListener; // 进度change监听
public void setProgressChangeListener(OnProgressChangedListener mProgressListener) {
this.mProgressListener = mProgressListener;
}
public SeekBarWithBubbleView(Context context) {
super(context);
}
public SeekBarWithBubbleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initView(attrs);
}
public SeekBarWithBubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 初始化数据
*
* @param attrs
*/
private void initView(AttributeSet attrs) {
if (null == attrs) {
return;
}
TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.SeekBarWithBubbleView);
mMax = ta.getInt(R.styleable.SeekBarWithBubbleView_seekBarMax, 100);
mMin = ta.getInt(R.styleable.SeekBarWithBubbleView_seekBarMin, 0);
mNowProgress = ta.getFloat(R.styleable.SeekBarWithBubbleView_nowProgress, mMin);
ta.recycle();
mSeekBarBgPaint = new Paint();
mSeekBarBgPaint.setAntiAlias(true);
mSeekBarBgPaint.setStrokeCap(Paint.Cap.ROUND);
mSeekBarBgPaint.setTextAlign(Paint.Align.CENTER);
mSeekBarBgPaint.setStrokeWidth(4);
mBubbleViewPaint = new Paint();
mBubbleViewPaint.setAntiAlias(true);
mBubbleViewPaint.setStrokeCap(Paint.Cap.ROUND);
mBubbleViewPaint.setTextAlign(Paint.Align.CENTER);
mBubbleViewPaint.setFakeBoldText(true);
mBubbleViewPaint.setTextSize(23);
mBubbleViewPaint.setColor(ContextCompat.getColor(mContext, R.color.tv_setting_bubble_text));
mBubbleViewPaint.setTextAlign(Paint.Align.CENTER);
setFocusable(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mViewWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
mViewHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
mBubbleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_common_seek_bar_thumb_enable);
mBubbleWidth = mBubbleBitmap.getWidth();
mBubbleHeight = mBubbleBitmap.getHeight();
mProgressExtraWidth = (float) (mBubbleWidth / 2.0);
// 获取气泡的中心点
setProgressValue((int) mNowProgress);
//mBubbleViewX = (float) (mProgressExtraWidth);
mBubbleViewY = (float) (57f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setLayerType(LAYER_TYPE_SOFTWARE, null);//对单独的View在运行时阶段禁用硬件加速
// 画出Seekbar背景
if (!mDisabledMode) {
mSeekBarBackground = BitmapFactory.decodeResource(getResources(), R.drawable.bg_seekbar_background_enabled);
} else {
mSeekBarBackground = BitmapFactory.decodeResource(getResources(), R.drawable.bg_seekbar_background_disabled);
}
canvas.drawBitmap(mSeekBarBackground, 0, 57, mSeekBarBgPaint);
// 绘制气泡背景图
if (!mDisabledMode) {
mBubbleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_common_seek_bar_thumb_enable);
} else {
mBubbleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_common_seek_bar_thumb_disabled);
}
canvas.drawBitmap(mBubbleBitmap, mBubbleViewX - mProgressExtraWidth, 0, mBubbleViewPaint);
if (!mDisabledMode) {
// 画笔设置了Align为Center,就不用减一半宽度了
String nowProgress = String.valueOf((int) mNowProgress);
if (mNowProgress >= 1 && mMin < 0) {
nowProgress = "+" + nowProgress;
}
canvas.drawText(nowProgress, mBubbleViewX, 25, mBubbleViewPaint);
}
}
public interface OnProgressChangedListener {
void onProgressChanged(SeekBarWithBubbleView bubbleSeekBar, int progress, boolean fromUser);
void onStartChangeProgress(SeekBarWithBubbleView bubbleSeekBar, int progress);
void onStopChangeProgress(SeekBarWithBubbleView bubbleSeekBar, int progress, boolean fromUser);
}
// 防止父类响应事件
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mDisabledMode) {
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
updateBubbleViewPosition(event.getX());
if (null != mProgressListener) {
mProgressListener.onStartChangeProgress(this, (int) mNowProgress);
}
break;
case MotionEvent.ACTION_MOVE:
updateBubbleViewPosition(event.getX());
if (null != mProgressListener) {
mProgressListener.onProgressChanged(this, (int) mNowProgress, true);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//setProgressValue((int) mNowProgress);
if (null != mProgressListener) {
if (mNowProgress < mMin) {
mNowProgress = mMin;
}
if (mNowProgress > mMax) {
mNowProgress = mMax;
}
mProgressListener.onStopChangeProgress(this, (int) mNowProgress, true);
}
break;
default:
break;
}
invalidate();
return true;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (null != mBubbleBitmap) {
mBubbleBitmap.recycle();
mBubbleBitmap = null;
}
if (null != mSeekBarBackground) {
mSeekBarBackground.recycle();
mSeekBarBackground = null;
}
}
/**
* 更新气泡位置及进度
*
* @param touchX
*/
private void updateBubbleViewPosition(float touchX) {
if (touchX < mProgressExtraWidth) {
mBubbleViewX = mProgressExtraWidth;
mNowProgress = mMin;
} else if (touchX > mViewWidth - mProgressExtraWidth) {
mBubbleViewX = (mViewWidth - mProgressExtraWidth);
mNowProgress = mMax;
} else {
mBubbleViewX = touchX;
mNowProgress = (mBubbleViewX - mProgressExtraWidth) / ((mViewWidth - 2 * mProgressExtraWidth) / (mMax - mMin)) + mMin;
}
}
/**
* 设置进度
*
* @param progress
*/
public void setProgressValue(int progress) {
if (progress < mMin) {
mNowProgress = mMin;
} else if (progress > mMax) {
mNowProgress = mMax;
} else {
mNowProgress = progress;
}
mBubbleViewX = (mNowProgress - mMin) * ((mViewWidth - 2 * mProgressExtraWidth) / (mMax - mMin)) + mProgressExtraWidth;
invalidate();
}
/**
* 设置模式
*
* @param disabledMode
*/
public void setMode(boolean disabledMode) {
this.mDisabledMode = disabledMode;
invalidate();
}
}
icon_common_seek_bar_thumb_enable
icon_common_seek_bar_thumb_disabled