我编写了一个简单的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
非常糟糕。
答案 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;
}
}
}