首页 文章

GestureDetector - 检测双击GridView项目虽然在onTouchEvent()中返回false

提问于
浏览
0

我写了一个简单的 ImageView 子类,我想用它来检测 GridView -items上的双击:

public class DoubleClickImageView extends ImageView {

public interface ClickListener {
    void onSingleClick();
    void onDoubleClick();
}

private ClickListener imageClickReceiver;
private GestureDetector gestureDetector;

@Override
public boolean onTouchEvent(MotionEvent event) {
    gestureDetector.onTouchEvent(event);
    // return super.onTouchEvent(event); does not work with gestureDetector
    // return false; does not work with gestureDetector
    return true; // works but breaks the rest of the application
}

public void setDoubleClickListener(ClickListener listener) {
    imageClickReceiver = listener;
}

public DoubleClickImageView(Context cx, AttributeSet attrs) {
    super(cx, attrs);
    gestureDetector = new GestureDetector(cx, new InternalClickListener());
}

private class InternalClickListener extends GestureDetector.SimpleOnGestureListener {

    @Override
    public boolean onSingleTapConfirmed(MotionEvent event) {
        if (imageClickReceiver != null) {
            imageClickReceiver.onSingleClick();
        }
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        if (imageClickReceiver != null) {
            imageClickReceiver.onDoubleClick();
        }
        return true;
    }

    @Override
    public boolean onDown(MotionEvent event) {
        //return true for onDown is required according to docs but does not help
        return true;
    }
}

}

GridView 包含使用此类显示的图像 .

问题是双击检测仅在 onTouchEvent 返回 true 时有效,否则 gestureDetector 不会检测到任何点击事件 .

但是,当我在 onTouchEvent 中返回 true 时,它会打破我的应用程序的其余部分,因为我还有一个全局 onTouchListener 来检测整个 GridView 上的滑动以及长按时的多选选择模式 .

如何解决这个问题,以便所有这三个功能一起工作?

Update: 我能够通过调试日志追查问题 . 事实证明,当初始onTouchEvent调用( MotionEvent.ACTION_DOWN )返回false时,相关的后续事件不会传递给 ImageView . 因此,GestureDetector无法理解它,因为它需要给定手势的所有相关MotionEvent .

我仍然需要针对此问题的解决方法 . 打破整个长按上下文操作栏只是因为我需要在 ImageView -subclass中使用 GestureDetector 是非常糟糕的 .

1 回答

  • 0

    在阅读http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/的触摸处理部分后,我终于找到了解决方法 .

    解决方法包括手动将MotionEvent传递给GridView的图像 . 因此,我扩展了DoubleClickImageView类和GridView的适配器类,如下所示:

    /**
         * A workaround to get all touch events of a gesture delivered to GridView-images,
         * although the onTouchEvent-callback has to return false to prevent breaking the
         * rest of the GridView-functionality. (these are swipe gestures and a contextual action bar in our case)
         * See http://stackoverflow.com/questions/39107566/detect-double-click-on-imageview-works-only-when-ontouchevent-returns-true#
         * http://stackoverflow.com/questions/39100565/gesturedetector-detect-doubleclick-on-gridview-items
         * for more information
         */
        public class DoubleClickImageView extends ImageView {
    
            private TouchEventForwarder touchEventForwarder;
            private ClickListener imageClickListener;
            private GestureDetector gestureDetector;
    
            /**
             * This needs to be called in the parent GridView adapter's getView() method
             **/
            public void setListeners(ClickListener dest, TouchEventForwarder src) {
                imageClickListener = dest;
                touchEventForwarder = src;
            }
    
            /**
             * The parent GridView adapter has to maintain an instance of this class
             **/
            public static class TouchEventForwarder {
    
                private DoubleClickImageView currentlyClickedImage;
    
                /**
                 * This needs to be called on each touch event received by the parent GridView
                 **/
                public void forwardTouchEvent(MotionEvent event) {
                    if (currentlyClickedImage != null) {
                        currentlyClickedImage.onForwardedTouchEvent(event);
                    }
                }
    
                private void setNewReceiver(DoubleClickImageView doubleClickImageView) {
                    currentlyClickedImage = doubleClickImageView;
                }
            }
    
            public interface ClickListener {
                void onSingleClick();
                void onDoubleClick();
            }
    
            private void onForwardedTouchEvent(MotionEvent event) {
                /** Use only forwarded events for gesture detection
                 * to prevent the evaluation of duplicate events **/
                gestureDetector.onTouchEvent(event);
            }
    
            @Override
            public boolean onTouchEvent(MotionEvent event) {
                /** Use the system listener to register the view at the event forwarder**/
                if (touchEventForwarder != null) {
                    touchEventForwarder.setNewReceiver(this);
                }
                return super.onTouchEvent(event); // always false
            }
    
            public DoubleClickImageView(Context cx, AttributeSet attrs) {
                super(cx, attrs);
                gestureDetector = new GestureDetector(cx, new InternalClickListener());
            }
    
            private class InternalClickListener extends GestureDetector.SimpleOnGestureListener {
                @Override
                public boolean onSingleTapConfirmed(MotionEvent event) {
                    if (imageClickListener != null) {
                        imageClickListener.onSingleClick();
                    }
                    return true;
                }
    
                @Override
                public boolean onDoubleTap(MotionEvent event) {
                    if (imageClickListener != null) {
                        imageClickListener.onDoubleClick();
                    }
                    return true;
                }
            }
        }
    

相关问题