自定义View —— 可删除 item 的 ListView (事件分发)
本文所用源码:https://github.com/HeXiaosa/ItemDeletableListView
本文由看这篇文章 https://blog.csdn.net/lmj623565791/article/details/22961279 以及结合 Andorid 开发艺术探索而来。
事件分发概述
Android 中触摸事件主要由 dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent 来控制。
触摸屏幕时,首先会触发 ViewGroup 的 dispathTouchEvent 方法,自定义 View 时,如果它在 ACTION_DOWN 返回 false, 则表示不再继续向下执行,事件到此结束,如果返回了 true, 则下次继续执行 dispatchTouchEvent 方法,返回 super.dispatchTouchEvent(ev) 则会执行 onInterceptTouchEvent/onTouchEvent.
View 是没有 onInterceptTouchEvent 方法的,因为事件传递到 View 之后是一定交给自己处理了。ViewGroup 的 onInterceptTouchEvent 方法 返回 true 表示 要拦截事件,给自己处理,返回 false 表示不拦截,传递给子 View 处理,执行子 View 的 dispatchTouchEvent 方法。
执行到 onTouchEvent 方法,返回 true 表示不再给它的 ViewGroup 处理,自己处理完就结束,返回 false 表示自己可以做一些操作,再执行它的 ViewGroup 的 onTouchEvent 方法。
可删除 item 的 ListView 思路
理解上面的描述之后,就可以结合上面文章中的例子来自己动手实现一个
- 从右向左滑动时,需要我们来处理(弹出PopupWindow),其余的交由 ListView 处理
- PopupWindow 是弹出状态时,再次触摸,则需要消失 PopupWindow, 事件到此结束
这里贴出 dispatchTouchEvent 和 onTouchEvent 的代码:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("ItemDeletableListView", "dispatchTouchEvent action : " + ev.getAction() + ", handleTouchEvent:" + handleTouchEvent + ", isPopupShow:" + isPopupShow);
Log.e("ItemDeletableListView", "dispatchTouchEvent mPwDelete.isShowing:" + mPwDelete.isShowing());
if (!handleTouchEvent) {
// 如果不需要处理触摸事件,那么久不做处理
return super.dispatchTouchEvent(ev);
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if (isPopupShow) {
// 已经展示了 popup 的话,再次触发 down 事件,则消失,并不再分发事件
mPwDelete.dismiss();
isPopupShow = false;
return false;
}
downX = ev.getX();
downY = ev.getY();
downPosition = pointToPosition(((int) downX), ((int) downY));
break;
case MotionEvent.ACTION_MOVE:
if (isPopupShow) {
// 如果 move 过程中展示了 popupwindow, 那么不再分发事件
return false;
}
x = ev.getX();
y = ev.getY();
if (downX-x > touchSlop && downX-x > Math.abs(downY-y)) {
isSliding = true;
} else {
isSliding = false;
}
break;
case MotionEvent.ACTION_UP:
isSliding = false;
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
Log.e("ItemDeletableListView", "onTouchEvent action : " + ev.getAction() + ", isSliding:" + isSliding + ", downPosition:" + downPosition);
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
if (isSliding) {
View child = getChildAt(downPosition);
if (child == null) {
return super.onTouchEvent(ev);
}
isPopupShow = true;
int x = getWidth()/2+mPwDelete.getWidth()/2;
int y = child.getTop()+child.getHeight()/2;
Log.e("TAG", "popup x:" + x + ", y:" + y);
mPwDelete.showAtLocation(child, Gravity.TOP | Gravity.LEFT, x, y);
mPwDelete.update();
mTvDelete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mDeleteItemListener.deleteItem(downPosition);
mPwDelete.dismiss();
isPopupShow = false;
}
});
}
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onTouchEvent(ev);
}