【问题标题】:onInterceptTouchEvent only gets ACTION_DOWNonInterceptTouchEvent 只获取 ACTION_DOWN
【发布时间】:2012-11-08 06:40:34
【问题描述】:

为什么ViewGroup 只能在onInterceptTouchEvent 中得到ACTION_DOWN?根据文档,只要返回 false,它就应该接收所有事件类型。 http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent%28android.view.MotionEvent%29 第 3 点。

示例代码:

public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new Container(this));
    }

    private class Container extends LinearLayout {

        public Container(Context context) {
            super(context);
            setBackgroundColor(0xFF0000FF);
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.i(TAG, "onInterceptTouchEvent");
            int action = ev.getActionMasked();
            switch (action) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onInterceptTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onInterceptTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onInterceptTouchEvent.ACTION_UP");
                break;
            }
            return super.onInterceptTouchEvent(ev);
        }
    }
}

【问题讨论】:

    标签: java android


    【解决方案1】:

    我会回答我自己的问题:只有当父级有一个从 onTouchEvent 返回“true”的子视图时才会调用 onInterceptTouchEvent。一旦孩子返回 true,父母现在就有机会拦截该事件。

    【讨论】:

    • 如果子级已经调度了事件,父级如何拦截?
    • 儿童不发送触摸事件(通常)。触摸事件从父级到子级迭代地冒泡。往下走是 onInterceptTouchEvent,往上走是 onTouchEvent。它会继续冒泡,直到有人返回 true。
    • 如果我有一个带有 onTouchListener 的视图,我将它添加到一个 ViewGroup。调用此侦听器,开始一些行为,然后返回 false。之后 ViewGroup 可以“拦截”事件吗?如果处理程序的代码已经执行?
    • 即使你在 ViewHolder 上设置了 setOnTouch 监听器,recycleview 的 SelectionTracker 仍然会被调用。有谁知道这是为什么?
    【解决方案2】:

    我遇到了同样的问题。我读过很多关于它的帖子:
    onInterceptTouchEvent only gets ACTION_DOWN
    onInterceptTouchEvent's ACTION_UP and ACTION_MOVE never gets called
    onInterceptTouchEvent, onTouchEvent only see ACTION_DOWN
    onInterceptTouchEvent never receives action_move

    我也读过安卓文档:
    http://developer.android.com/training/gestures/viewgroup.html
    http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)

    所有答案都是一样的。试了很多次,总是上不了onInterceptTouchEvent () 如果不是 down 事件则被调用。

    我看了源代码,我猜有些地方变了:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }
    
        boolean handled = false;
        if (onFilterTouchEventForSecurity(ev)) {
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;
    
            // Handle an initial down.
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }
    
            // Check for interception.
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }
    


    根据上面的代码,onInterceptTouchEvent(ev) 只有在MotionEvent.ACTION_DOWN 时才会被调用,这是我们尝试发现的。所以,我猜是,代码改变了,但文档没有。

    如果您想监视或监视所有事件,包括发送到子视图的事件,您可以像这样覆盖dispatchTouchEvent()

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        MyLog.d(MyLog.DEBUG, "dispatchTouchEvent(): "+event.getAction());
        if (isEnabled()) {
            MyLog.d(MyLog.DEBUG, "dispatchTouchEvent()2: "+event.getAction());
    
            processEvent(event);//here you get all events include move & up
    
            super.dispatchTouchEvent(event);
    
            return true; //to keep receive event that follow down event
        }
        return super.dispatchTouchEvent(event);
    }
    

    我的可运行代码位于:https://github.com/maxyou/gesturebutton/blob/master/src/com/maxproj/gesturebutton/GestureButtonLayout.java

    【讨论】:

    • 非常感谢!我花了大约 3 个小时尝试不同的解决方案,但这个真的很好!
    【解决方案3】:

    dispatchTouchEvent、onInterceptTouchEvent、requestDisallowInterceptTouchEvent

    [Touch event flow]

    官方doc

    Activity.dispatchTouchEvent(MotionEvent) - 这允许您的 Activity 在将所有触摸事件分派到窗口之前拦截它们。

    ViewGroup.onInterceptTouchEvent(MotionEvent) - 这允许 ViewGroup 在事件被分派到子视图时观察它们。它是递归函数(从父级到父级)

    ViewParent.requestDisallowInterceptTouchEvent(boolean) - 在父视图上调用它以指示它不应使用 onInterceptTouchEvent(MotionEvent) 拦截触摸事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多