问题
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