GestureDetector - Detect double click in GridView item's although returning false in onTouchEvent()

别来无恙 提交于 2019-12-12 03:48:47

问题


I wrote a simple subclass of ImageView that I want to use to detect double clicks on 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;
    }
}

}

The GridView consists of Images that are displayed using this class.

The problem is that the double click detection works only when onTouchEvent returns true, otherwise the gestureDetector does not detect any click event.

However, when I return true in the onTouchEvent, it breaks the rest of my application, since I have also a global onTouchListener to detect swipes over the whole GridView and a multiple choice select mode with long press.

How can I solve this problem so that all of these three features work together?

Update: I was able to trace down the problem with debug logs. It turned out that when the initial onTouchEvent-call (MotionEvent.ACTION_DOWN) returns false, the related follow-up-events are not delivered to the ImageView. Therefore the GestureDetector can not make any sense of it, since it needs all related MotionEvents of a given gesture.

I still need a workaround for this issue. Breaking the whole long-press contextual action bar just because I need to use a GestureDetector in an ImageView-subclass is extremely bad.


回答1:


I was finally able to find a workaround after reading the touch handling section of http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/.

The workaround consists of manually passing MotionEvent's to the images of the GridView. Therefore I extended the DoubleClickImageView class and my GridView's adapter class as follows:

 

    /**
     * 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;
            }
        }
    }



来源:https://stackoverflow.com/questions/39107566/gesturedetector-detect-double-click-in-gridview-items-although-returning-fals

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!