由于seekbar的拖动更改进度的监听是由AbsSeekBar的onTouchEvent来触发 因此可以通过重新onTouchEvent来实现
AbsSeekBar的onTouchEvent源码如下
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!mIsUserSeekable || !isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (isInScrollingContainer()) {
mTouchDownX = event.getX();
} else {
startDrag(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mIsDragging) {
trackTouchEvent(event);
} else {
final float x = event.getX();
if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) {
startDrag(event);
}
}
break;
case MotionEvent.ACTION_UP:
if (mIsDragging) {
trackTouchEvent(event);
onStopTrackingTouch();
setPressed(false);
} else {
onStartTrackingTouch();
trackTouchEvent(event);
onStopTrackingTouch();
}
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
if (mIsDragging) {
onStopTrackingTouch();
setPressed(false);
}
invalidate(); // see above explanation
break;
}
return true;
}
由源码可见OnSeekBarChangeListener 的回调是在MotionEvent.ACTION_UP和MotionEvent.ACTION_CANCEL进行执行的 所以可以根据用户按住的时间,来决定是否这两个action是否调用父类的action
代码如下
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.AppCompatSeekBar;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* Created by jsc on 2017/7/13.
*/
public class LongTouchSeekBar extends AppCompatSeekBar {
private long downTime;
private LongClickListener longClickListener;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1 && !hasLongTouch) {
hasLongTouch = true;
if (longClickListener != null) longClickListener.onLongClick();
}
}
};
private float lastY;
private float lastX;
public LongTouchSeekBar(Context context) {
this(context, null);
}
public LongTouchSeekBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LongTouchSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private boolean hasLongTouch = false;//是否已经执行长按操作
private boolean possibleLongTouch = true;//可能是长按
@Override
public boolean onTouchEvent(MotionEvent event) {
float y = event.getY();
float x = event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
hasLongTouch = false;//初始化 是否已经执行过长按事件
possibleLongTouch = true;//初始化 是否可能为长按模式
lastY = y;
lastX = x;
downTime = System.currentTimeMillis();//记录按下的时间
if (!handler.hasMessages(1)) {//如果消息队列中已有消息 则不在重新发送
handler.sendEmptyMessageDelayed(1, 800);
}
return super.onTouchEvent(event);
case MotionEvent.ACTION_MOVE:
//移动时如果x|y滑动了一段距离 则不可能为长按事件 即将 possibleLongTouch置为false
if (lastX != 0 && lastY != 0 && (Math.abs(y - lastY) > 5 || Math.abs(x - lastX) > 5)) {
possibleLongTouch = false;
handler.removeMessages(1);
return super.onTouchEvent(event);
}
lastY = y;
lastX = x;
break;
case MotionEvent.ACTION_UP:
lastX = 0;
lastY = 0;
handler.removeMessages(1);
if (System.currentTimeMillis() - downTime > 800 && possibleLongTouch) {
if (!hasLongTouch) {//如果已经执行过长按操作 则不需要再次执行
hasLongTouch = true;
if (longClickListener != null) {
longClickListener.onLongClick();
}
}
return true;
}
return super.onTouchEvent(event);
case MotionEvent.ACTION_CANCEL:
handler.removeMessages(1);
lastX = 0;
lastY = 0;
return super.onTouchEvent(event);
}
return false;
}
public void setLongClickListener(LongClickListener longClickListener) {
this.longClickListener = longClickListener;
}
public interface LongClickListener {
void onLongClick();
}
}