/**
* 带下标的seekBar
*/
public class CustomSeekbar extends View {
private final String TAG = "CustomSeekbar";
private Paint mPaint;
private Paint mTextPaint;
private Bitmap mThumb;
private int mThumbOffset = 0;
private int mProgress = 2;
private int mTextSize;
private int mTextSpace = 20;
private int mTextColor = Color.parseColor("#969696");
private Rect mRectText;
private List<String> mTitles;
private int mTrackHeight = 6;
private int mTrackColor = Color.GRAY;
private int mTrackOffset = 0;
private int mProgressTrackColor = Color.BLACK;
private OnProgressChangedListener mOnProgressChangedListener;
public CustomSeekbar(Context context) {
super(context);
}
public CustomSeekbar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomSeekbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint(Paint.DITHER_FLAG);
mPaint.setAntiAlias(true);
mTextPaint = new Paint(Paint.DITHER_FLAG);
mTextPaint.setAntiAlias(true);
mRectText = new Rect();
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekbar);
mTextSpace = a.getDimensionPixelSize(R.styleable.CustomSeekbar_csb_text_space, getFontHeight() * 2);
mTextColor = a.getColor(R.styleable.CustomSeekbar_csb_text_color, Color.BLUE);
mTextSize = a.getDimensionPixelSize(R.styleable.CustomSeekbar_csb_text_size, 10);
mThumb = BitmapFactory.decodeResource(getResources(), a.getResourceId(R.styleable.CustomSeekbar_csb_thumb, R.drawable.group_set_thumb));
mTrackHeight = a.getDimensionPixelOffset(R.styleable.CustomSeekbar_csb_track_height, dp2px(mTrackHeight));
mTrackColor = a.getColor(R.styleable.CustomSeekbar_csb_track_color, mTrackColor);
mProgressTrackColor = a.getColor(R.styleable.CustomSeekbar_csb_progress_track_color, mProgressTrackColor);
mProgress = a.getInteger(R.styleable.CustomSeekbar_csb_progress, 0);
mTrackOffset = a.getDimensionPixelOffset(R.styleable.CustomSeekbar_csb_track_offset, 0);
mThumbOffset = a.getDimensionPixelOffset(R.styleable.CustomSeekbar_csb_thumb_offset , 0);
int dataId = a.getResourceId(R.styleable.CustomSeekbar_csb_data, 0);
if (dataId != 0) {
String[] data = getResources().getStringArray(dataId);
initData(Arrays.asList(data));
} else {
initData(null);
}
a.recycle();
}
/**
* 实例化后调用,设置bar的段数和文字
*/
public void initData(List<String> data) {
if (data != null) {
mTitles = data;
} else {
mTitles = new ArrayList<>();
mTitles.add("低");
mTitles.add("中");
mTitles.add("高");
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int width = widthSize;
int height = getPaddingTop() + getPaddingBottom() + Math.max(getThumbHeight(), mTrackHeight)
+ mTextSpace + getFontHeight();
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int startX = getPaddingLeft() + getThumbHeight() / 2;
int startY = getPaddingTop() + (getThumbHeight() > mTrackHeight ? getThumbHeight() - mTrackHeight : 0) / 2;
drawTrack(canvas, startX, startY);
drawProgressTrack(canvas, startX, startY);
drawThumb(canvas, startX, startY);
drawText(canvas, startX, startY);
}
private void drawTrack(Canvas canvas, int startX, int startY) {
int endX = getWidth() - getPaddingRight() - getThumbWidth() / 2 + mTrackOffset;
int y = startY;
mPaint.setColor(mTrackColor);
canvas.drawRect(startX - mTrackOffset, startY, endX, startY + mTrackHeight, mPaint);
canvas.drawCircle(startX - mTrackOffset, y + mTrackHeight / 2, mTrackHeight / 2, mPaint);
canvas.drawCircle(endX, y + mTrackHeight / 2, mTrackHeight / 2, mPaint);
}
private void drawProgressTrack(Canvas canvas, int startX, int startY) {
if (getProgress() == 0) {
return;
}
mPaint.setColor(mProgressTrackColor);
int endX = startX + getProgress() * getItemWidth();
if (getProgress() == getMax()) {
endX += mTrackOffset;
}
int y = startY;
canvas.drawRect(startX - mTrackOffset, startY, endX, startY + mTrackHeight, mPaint);
canvas.drawCircle(startX - mTrackOffset, y + mTrackHeight / 2, mTrackHeight / 2, mPaint);
canvas.drawCircle(endX, y + mTrackHeight / 2, mTrackHeight / 2, mPaint);
}
private void drawThumb(Canvas canvas, int startX, int startY) {
int x = startX + getProgress() * getItemWidth() - getThumbWidth() / 2;
int y = getThumbHeight() > mTrackHeight ? 0 : (mTrackHeight - getThumbHeight()) / 2;
if (getProgress() == 0) {
x -= mThumbOffset;
} else if (getProgress() == getMax()) {
x += mThumbOffset;
}
canvas.drawBitmap(mThumb, x, y, mPaint);
}
private void drawText(Canvas canvas, int startX, int startY) {
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(mTextSize);
for (int i = 0; i <= getMax(); i++) {
String title = mTitles.get(i);
if (title == null || title.isEmpty()) {
continue;
}
int x = startX + i * getItemWidth() - getTextWidth(title) / 2;
int y = getPaddingTop() + Math.max(getThumbHeight(), mTrackHeight) + mTextSpace + getFontHeight() / 2;
canvas.drawText(title, x, y, mTextPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int progress = findProgress(event.getX(), event.getY());
if (progress < 0) {
break;
}
setProgress(progress);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mOnProgressChangedListener != null) {
mOnProgressChangedListener.onProgressChanged(this, getProgress());
}
break;
}
return true;
}
private int findProgress(float x, float y) {
Log.d(TAG, "findProgress: x: " + x + ", y: " + y);
if (x <= getLeft() + getPaddingLeft() + getThumbWidth() / 2) {
return 0;
} else if (x >= getRight() - getPaddingRight() - getThumbWidth() / 2) {
return getMax();
}
if (y >= getBottom() - getPaddingBottom() - getFontHeight()) {
return -1;
}
int progress = (int) ((x - getLeft() - getPaddingLeft() - getThumbWidth() / 2) / getItemWidth() + 0.5);
progress = progress > getMax() ? getMax() : progress;
return progress;
}
public int getMax() {
if (mTitles == null || mTitles.size() <= 1) {
return 0;
}
return mTitles.size() - 1;
}
public void setProgress(int progress) {
mProgress = progress > getMax() ? getMax() : progress;
invalidate();
}
public int getProgress() {
return mProgress;
}
private int getThumbWidth() {
if (mThumb == null || mThumb.isRecycled()) {
return 0;
}
return mThumb.getWidth();
}
private int getThumbHeight() {
if (mThumb == null || mThumb.isRecycled()) {
return 0;
}
return mThumb.getHeight();
}
private int getItemWidth() {
return (getWidth() - getPaddingLeft() - getPaddingRight() - getThumbWidth()) / (mTitles.size() - 1);
}
private int getFontHeight() {
mTextPaint.setTextSize(mTextSize);
mTextPaint.getTextBounds("w", 0, 1, mRectText);
return mRectText.height();
}
private int getTextWidth(String text) {
mTextPaint.setTextSize(mTextSize);
mTextPaint.getTextBounds(text, 0, text.length(), mRectText);
return mRectText.width();
}
public OnProgressChangedListener getOnProgressChangedListener() {
return mOnProgressChangedListener;
}
public void setOnProgressChangeListener(OnProgressChangedListener mOnProgressChangedListener) {
this.mOnProgressChangedListener = mOnProgressChangedListener;
}
public interface OnProgressChangedListener {
void onProgressChanged(CustomSeekbar seekBar, int progress);
}
static int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
Resources.getSystem().getDisplayMetrics());
}
static int sp2px(int sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
Resources.getSystem().getDisplayMetrics());
}
}
<declare-styleable name="CustomSeekbar">
<attr name="csb_data" format="reference" />
<attr name="csb_text_color" format="color" />
<attr name="csb_text_size" format="dimension" />
<attr name="csb_text_space" format="dimension" />
<attr name="csb_thumb" format="reference" />
<attr name="csb_progress" format="integer" />
<attr name="csb_track_color" format="color" />
<attr name="csb_progress_track_color" format="color" />
<attr name="csb_track_height" format="dimension" />
<attr name="csb_track_offset" format="dimension"/>
<attr name="csb_thumb_offset" format="dimension"/>
<attr name="csb_text_potions">
<enum name="top" value="1" />
<enum name="bottom" value="2" />
</attr>
</declare-styleable>