Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
167 views
in Technique[技术] by (71.8m points)

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

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 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. If the initial onTouchEvent-call (MotionEvent.ACTION_DOWN) returns false,then 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...