我遇到了OnDragListener
的奇怪问题。我的目标视图使ACTION_DROP
事件正常并处理它;但它永远不会收到ACTION_DRAG_STARTED
或ACTION_DRAG_ENDED
事件(实际上除了丢弃之外它永远不会收到任何事件)。
可能导致这种情况的原因是什么?这是一个问题,因为当掉落发生在目标之外时,我无法处理这种情况。
我找到this question,但答案对我来说并不清楚。任何想法都非常感激。
我的可拖动视图有OnTouchListener
:
@Override
public boolean onTouch(View v, MotionEvent ev) {
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
startPointX = ev.getX();
startPointY = ev.getY();
isOnClick = true;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (isOnClick) {
isOnClick = false;
// handle single click
}
break;
case MotionEvent.ACTION_MOVE:
if (isOnClick && movePassesThreshold(ev)) {
isOnClick = false;
draggableView.startDrag(...);
}
break;
default:
break;
}
return true;
}
目标视图包含此OnDragListener
:
@Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
Log.v(TAG, "drag started");
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
Log.v(TAG, "drop");
// handle drop
break;
case DragEvent.ACTION_DRAG_ENDED:
Log.v(TAG, "drag ended");
break;
default:
return false;
}
return true;
}
答案 0 :(得分:4)
这是ViewGroup的一个已知问题:
https://code.google.com/p/android/issues/detail?id=25073
按照该链接的建议覆盖dispatchDragEvent函数对我有用:
@Override
public boolean dispatchDragEvent(DragEvent ev){
boolean r = super.dispatchDragEvent(ev);
if (r && (ev.getAction() == DragEvent.ACTION_DRAG_STARTED
|| ev.getAction() == DragEvent.ACTION_DRAG_ENDED)){
// If we got a start or end and the return value is true, our
// onDragEvent wasn't called by ViewGroup.dispatchDragEvent
// So we do it here.
onDragEvent(ev);
}
return r;
}
答案 1 :(得分:1)
我的解决方案就是解决这个问题:当我的OnTouchListener
获得ACTION_UP时,设置一个1秒的延迟runnable来检查视图是否仍在拖动。如果OnDragListener
收到了丢弃,则runnable什么都不做;但如果没有,则runnable调用会停止拖动以清理并将视图重置为其先前的位置。
case MotionEvent.ACTION_UP:
if (isOnClick) {
isOnClick = false;
// handle single click
} else if (draggableView.isDragging()) {
uiHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (draggableView.isDragging()) {
// Drop never got received, so call stopDrag
draggableView.stopDrag();
}
}
}, 1000);
}
break;
答案 2 :(得分:0)
这就是我这样做的方式。我不知道它是否适合你,但仍然张贴。
@Override
public boolean onTouch(View v, MotionEvent event) {
final ClipData data = ClipData.newPlainText("position",position + "");
v.startDrag(data, pieceDragShadowBuilder, v, 0);
return true;
}
然后在我的听众中:
@Override
public boolean onDrag(View pV, DragEvent pEvent) {
final int dragAction = pEvent.getAction();
View dragView = (View) pEvent.getLocalState();
final FrameLayout container = (FrameLayout) pV;
if (dragAction == DragEvent.ACTION_DRAG_STARTED)
{
}
else if (dragAction == DragEvent.ACTION_DRAG_ENTERED)
{
}
else if (dragAction == DragEvent.ACTION_DRAG_EXITED)
{
}
else if (dragAction == DragEvent.ACTION_DROP)
{
}
现在我从您的代码中看到的唯一区别是我在startDrag()
中调用onTouch()
方法,无论MOVE或UP或CANCEL的具体事件如何。