GestureDetector - 检测双击GridView项目虽然在onTouchEvent()

时间:2016-08-23 17:39:03

标签: java android gridview double-click touchscreen

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

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不会检测到任何点击事件。

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

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

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

我仍然需要解决此问题。打破整个长按上下文操作栏只是因为我需要在GestureDetector - 子类中使用ImageView非常糟糕。

1 个答案:

答案 0 :(得分: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;
            }
        }
    }