欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义View —— 可删除 item 的 ListView (事件分发)

程序员文章站 2022-07-13 15:30:48
...

本文所用源码: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 思路

理解上面的描述之后,就可以结合上面文章中的例子来自己动手实现一个

  1. 从右向左滑动时,需要我们来处理(弹出PopupWindow),其余的交由 ListView 处理
  2. 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);
}
相关标签: 自定义View