有个需求,ListView列表支持筛选。点击筛选Tabs时候,在Tabs下方弹出FilterCard,遮盖在ListView列表上层,此时不能滑动Tabs,否则界面好尴尬,只有FilterCard消失时候,列表才回复滑动。已知Tabs是listView的一个HeaderView。要求Tabs支持点击切换,但是不能上下滑动,此刻要做的就是监听FilterCard的可见性,VISIBLE时候禁止上下滑动,否则支持滑动。
我们可以设置listView.setEnable(false);但是代价就是连Tabs也不支持点击了。我们需要的仅仅是禁止其上下滑动。事件分发监控ACTION_MOVE才是解决问题的根本思路。我们知道, 点击事件都能通过触摸后移动来取消这个事件,我们重写dispatchTouchEvent()时候,一定要保证该体验不能丢失。
代码实现如下:
/**
* Created by iblade.Wang on 2019/2/13 14:54
* 该ListView,可以通过setScrollEnable()设置listView是否支持上下滑动
*/
public class ScrollListView extends ListView {
public ScrollListView(Context context) {
super(context);
}
public ScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private boolean mIsScroll = true;
/**
* 是否支持上下滑动
*
* @param isScroll 滑动与否
*/
public void setScrollEnable(boolean isScroll) {
mIsScroll = isScroll;
}
private int mPosition;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int actionMasked = ev.getActionMasked() & MotionEvent.ACTION_MASK;
if (actionMasked == MotionEvent.ACTION_MOVE && !mIsScroll) {
return true;
}
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 记录手指按下时的位置
mPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
return super.dispatchTouchEvent(ev);
}
// 手指抬起时
if (actionMasked == MotionEvent.ACTION_UP
|| actionMasked == MotionEvent.ACTION_CANCEL) {
// 手指按下与抬起都在同一个视图内,交给父控件处理,这是一个点击事件
if (pointToPosition((int) ev.getX(), (int) ev.getY()) == mPosition) {
super.dispatchTouchEvent(ev);
} else {
// 如果手指已经移出按下时的Item,说明是滚动行为,清理Item pressed状态, 点击事件都能通过触摸后移动来取消这个事件
setPressed(false);
invalidate();
return true;
}
}
return super.dispatchTouchEvent(ev);
}
}