package com.susion.boring.music.view;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.susion.boring.R;
/**
* Created by susion on 16/11/10.
* 自定义的SeekBar
*/
public class MediaSeekBar extends View {
private Context context;
private MediaSeekBarListener listener;
private OnProgressListener progressListener;
int maxProgress;
int hasBufferProgress;
int currentProgress = 0;
int width;
int height;
private int centerY; // MediaSeekBar height's half
private Bitmap thumb;
private float thumbPos; // thumb's center point (center x)
private final int DEFAULT_SIZE = 100;
private float halfThumbWidth;
private Paint paint;
private int hasPlayColor;
private int originBackgroundColor;
private int hasBufferColor;
private int progressLineWidth;
float x;
float y;
float preDragX;
private static final float CALL_DRAGGING_FREQUENCY = 80;
private int currentTouchState = NO_TOUCH;
private static final int NO_TOUCH = 1;
private static final int CLICK_THUMB = 2;
private static final int START_DRAG_THUMB = 3;
private static final int DRAGGING_THUMB = 4;
private static final int STOP_DRAG_THUMB = 5;
private static final int CLICK_PROGRESS = 6;
private boolean isStartDrawThumb = false;
private int PROGRESS_CLICK_RANGE = 15;
private boolean canOperator = false;
public MediaSeekBar(Context context) {
super(context);
this.context = context;
init(null);
}
public MediaSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init(attrs);
}
public MediaSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init(attrs);
}
private void init(AttributeSet attrs) {
initDefaultStyle();
initAttributes(attrs);
initPaint();
}
private void initDefaultStyle() {
Resources resources = context.getResources();
hasPlayColor = resources.getColor(R.color.has_play_color);
originBackgroundColor = resources.getColor(R.color.origin_background_color);
hasBufferColor = resources.getColor(R.color.has_buffer_color);
maxProgress = 100;
progressLineWidth = dpToPx(2);
thumb = (new MediaPlayerThumb(dpToPx(20), dpToPx(20), context)).getBitmap();
}
private void initAttributes(AttributeSet attrs) {
if (attrs != null) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.MediaSeekBar);
hasBufferColor = ta.getColor(R.styleable.MediaSeekBar_hasBufferColor, hasBufferColor);
hasPlayColor = ta.getColor(R.styleable.MediaSeekBar_hasPlayColor, hasPlayColor);
originBackgroundColor = ta.getColor(R.styleable.MediaSeekBar_originBackgroundColor, originBackgroundColor);
maxProgress = ta.getInt(R.styleable.MediaSeekBar_maxProgress, maxProgress);
progressLineWidth = ta.getDimensionPixelOffset(R.styleable.MediaSeekBar_progressWidth, progressLineWidth);
canOperator = ta.getBoolean(R.styleable.MediaSeekBar_canOperator, true);
Drawable tempDrawable = ta.getDrawable(R.styleable.MediaSeekBar_customThumb);
if (tempDrawable != null) {
thumb = getBitmapFromDrawable(tempDrawable);
}
ta.recycle();
}
}
private void initPaint() {
paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
paint.setAntiAlias(true);
paint.setStrokeWidth(progressLineWidth);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.EXACTLY) {
width = MeasureSpec.getSize(widthMeasureSpec);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
width = DEFAULT_SIZE;
}
if (heightSpecMode == MeasureSpec.EXACTLY) {
height = MeasureSpec.getSize(heightMeasureSpec);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
height = DEFAULT_SIZE;
}
if (thumb != null) {
int thumbHeight = thumb.getHeight();
if (thumbHeight > height) {
//scale thumb to fit
Matrix matrix = new Matrix();
float scaleValue = (float) (height * 1.0 / thumbHeight);
matrix.setScale(scaleValue, scaleValue);
thumb = Bitmap.createBitmap(thumb, 0, 0, thumb.getWidth(), thumb.getHeight(), matrix, true);
}
}
centerY = height / 2;
if (height < PROGRESS_CLICK_RANGE * 2) {
PROGRESS_CLICK_RANGE = height / 2;
}
halfThumbWidth = thumb.getWidth() * 1.0f / 2;
thumbPos = halfThumbWidth;
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(0, centerY);
drawOriginProgressLine(canvas);
drawHasBufferProgressLine(canvas);
drawHasPlayProgressLine(canvas);
drawThumb(canvas);
canvas.save();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!canOperator) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
if (isPressThumb(x, y)) {
currentTouchState = CLICK_THUMB;
}
if (isClickProgress(x, y) && currentTouchState != CLICK_THUMB) {
currentTouchState = CLICK_PROGRESS;
setCurrentProgress(translateXtoProgress(x));
}
break;
case MotionEvent.ACTION_MOVE:
if (currentTouchState == CLICK_THUMB || currentTouchState == START_DRAG_THUMB
|| currentTouchState == DRAGGING_THUMB) {
setThumbPositionByAxis(event.getX());
if (!isStartDrawThumb) {
isStartDrawThumb = true;
preDragX = event.getX();
currentTouchState = START_DRAG_THUMB;
notifyListener(translateXtoProgress(event.getX()));
} else {
currentTouchState = DRAGGING_THUMB;
// control call onDraggingThumb's frequency
if (event.getX() - preDragX > CALL_DRAGGING_FREQUENCY) {
preDragX = event.getX();
notifyListener(translateXtoProgress(event.getX()));
}
}
}
break;
case MotionEvent.ACTION_UP:
if (currentTouchState == CLICK_PROGRESS) {
notifyListener(getCurrentProgress());
if (progressListener != null) {
progressListener.onSeekToNewProgress(getCurrentProgress());
}
}
if (isStartDrawThumb && currentTouchState == DRAGGING_THUMB) {
isStartDrawThumb = false;
currentTouchState = STOP_DRAG_THUMB;
notifyListener(getCurrentProgress());
if (progressListener != null) {
progressListener.onSeekToNewProgress(getCurrentProgress());
}
}
if (currentTouchState == CLICK_THUMB) {
notifyListener(0);
}
currentTouchState = NO_TOUCH;
break;
}
return true;
}
private void notifyListener(int currentProgress) {
if (listener == null) return;
if (currentTouchState == CLICK_THUMB) {
// listener.onThumbClick();
}
if (currentTouchState == CLICK_PROGRESS) {
listener.onProgressChange(currentProgress);
}
if (currentTouchState == START_DRAG_THUMB) {
listener.onStartDragThumb(currentProgress);
}
if (currentTouchState == STOP_DRAG_THUMB) {
listener.onStopDragThumb(currentProgress);
}
if (currentTouchState == DRAGGING_THUMB) {
listener.onDraggingThumb(currentProgress);
}
}
private boolean isPressThumb(float x, float y) {
//expand touch range of thumb
float left = thumbPos - thumb.getWidth();
int top = 0;
float right = thumbPos + thumb.getWidth();
int bottom = height;
RectF thumbRect = new RectF(left, top, right, bottom);
return thumbRect.contains(x, y);
}
private boolean isClickProgress(float x, float y) {
return y > centerY - PROGRESS_CLICK_RANGE && y < centerY + PROGRESS_CLICK_RANGE;
}
private void drawOriginProgressLine(Canvas canvas) {
paint.setColor(originBackgroundColor);
canvas.drawLine(0, 0, width, 0, paint);
}
private void drawHasBufferProgressLine(Canvas canvas) {
int stopX = (int) ((hasBufferProgress * 1.0 / maxProgress) * width);
paint.setColor(hasBufferColor);
canvas.drawLine(0, 0, stopX, 0, paint);
}
private void drawHasPlayProgressLine(Canvas canvas) {
paint.setColor(hasPlayColor);
canvas.drawLine(0, 0, getLineStopX(), 0, paint);
}
public float getLineStopX() {
// 0 - 100 corresponding to halfThumbWidth - (width - halfThumbWidth)
float f = (currentProgress * 1.0f / maxProgress) * (width - thumb.getWidth()) + halfThumbWidth;
return f;
}
private void drawThumb(Canvas canvas) {
float leftX = (float) ((currentProgress * 1.0 / maxProgress) * (width - thumb.getWidth()) + halfThumbWidth) - halfThumbWidth;
// float leftX = thumbPos - halfThumbWidth;
int top = thumb.getHeight() / 2 * -1;
canvas.drawBitmap(thumb, getThumbLeft(leftX), top, paint);
}
public float getThumbLeft(float left) {
if (left < 0) return 0;
if (left > width - thumb.getWidth()) return width - thumb.getWidth();
return left;
}
public void setHasBufferProgress(int bufferProgress) {
if (bufferProgress > maxProgress) {
hasBufferProgress = maxProgress;
} else {
hasBufferProgress = bufferProgress;
}
invalidate();
}
public void setCurrentProgress(int progress) {
if (progress > maxProgress) {
currentProgress = maxProgress;
} else {
currentProgress = progress;
}
setThumbPositionByProgress(currentProgress);
invalidate();
}
private void setThumbPositionByAxis(float x) {
setCurrentProgress(translateXtoProgress(x));
}
private void setThumbPositionByProgress(int currentProgress) {
if (currentProgress == 0) {
thumbPos = halfThumbWidth;
return;
}
if (currentProgress == maxProgress) {
thumbPos = width - halfThumbWidth;
return;
}
thumbPos = (float) ((currentProgress * 1.0 / maxProgress) * (width - thumb.getWidth()) + halfThumbWidth);
int a = 0;
}
private int translateXtoProgress(float x) {
if (x < halfThumbWidth) return 0;
if (x > width - halfThumbWidth) return maxProgress;
return (int) (maxProgress * (x / width) + 0.5f);
}
public int dpToPx(int values) {
float density = context.getResources().getDisplayMetrics().density;
return (int) (values * density + 0.5f);
}
public void setThumb(Drawable d) {
thumb = getBitmapFromDrawable(d);
}
public void setMediaSeekBarListener(MediaSeekBarListener listener) {
this.listener = listener;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
}
public int getCurrentProgress() {
return currentProgress;
}
public int getHasBufferProgress() {
return hasBufferProgress;
}
public boolean isCanOperator() {
return canOperator;
}
public void setCanOperator(boolean canOperator) {
this.canOperator = canOperator;
}
public int getMaxProgress() {
return maxProgress;
}
public void setProgressListener(OnProgressListener progressListener) {
this.progressListener = progressListener;
}
public Bitmap getBitmapFromDrawable(Drawable drawable) {
Bitmap bitmap;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
public interface MediaSeekBarListener {
void onStartDragThumb(int currentProgress);
void onDraggingThumb(int currentProgress);
void onStopDragThumb(int currentProgress);
void onProgressChange(int currentProgress); // call at click progress drag thumb
}
public interface OnProgressListener {
void onSeekToNewProgress(int newProgress);
}
}