?? 最近要實現(xiàn)一個需求,seekbar 只允許拖動調(diào)整,不允許點擊調(diào)整進度條位置。于是本著不去重復發(fā)明輪子的精神去網(wǎng)上找方法...
首先是嘗試了這么一種寫法:
oldProgress = mSeekBar.getProgress();
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
if(progress > oldProgress + 3 || progress < oldProgress - 3){
seekBar.setProgress(oldProgress);
return;
}
seekBar.setProgress(progress);
oldProgress = progress;
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
??從代碼邏輯來看,沒有任何問題,在onProgressChanged中判斷新的progress與oldprogress的差距,超出一定范圍就認為是點擊調(diào)整,就return掉,不改變進度條位置。
??但是實操下來,發(fā)現(xiàn)這種方式 點擊調(diào)整確實被攔截掉了,但是拖拽操作只有在緩慢拖拽的情況下才會跟手,快速滑動時不跟手,體驗很不好。原因是即使是拖拽的情況,onProgressChanged 的回調(diào)里 progress并不是連續(xù)的,快速拖拽時,方法中的progress參數(shù)可能跨度也非常大,也會被認為是點擊操作而被攔截。于是只能自定義SeekBar,攔截它的Touch事件來實現(xiàn)。代碼如下:
package com.example.sahara.customseekbar;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SeekBar;
public class CustomSeekBar extends SeekBar {
private Rect mRect;
private boolean mInterceptClick = false;
public CustomSeekBar(Context context) {
super(context);
}
public CustomSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Drawable drawable = getThumb();
mRect = drawable.getBounds();
if (mInterceptClick) {
return interceptAction(x, y);
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 主要邏輯都在這里,主要思路就是判斷觸摸點位置是否在進度條的小圓點里
*
* 這里分別向左右擴大了50像素,目的是為了優(yōu)化拖拽體驗,因為小圓點非常小,
* 拖拽時可能沒那么準確的觸摸到小圓點區(qū)域,導致很難進行拖拽
*/
private boolean interceptAction(float x, float y) {
if(mRect == null){
return true;
}
Rect rect = new Rect(mRect.left - 50, mRect.top, mRect.right + 50, mRect.bottom);
if (rect != null) {
if (rect.contains((int) (x), (int) (y))) {
return true;
} else {
return false;
}
} else {
return true;
}
}
public void interceptAction(boolean interceptClick) {
mInterceptClick = interceptClick;
}
}
mCustomSeekBar = findViewById(R.id.custom_seekbar);
mCustomSeekBar.interceptAction(true);
至此一個非常絲滑的 seekbar 就完成了...如果想完成更多的攔截需求,都可以參照這種方式~

GIF.gif