Android的拖放操作ACTION_DRAG_ENDED不能触发

我真的有时间搞这个,到目前为止找不到有相关经验的朋友。 这是我最后的function之前,我发布我的第一个APP,所以这让我疯狂,已经陷入了与它结束在视线中!

如果将对象放在可接受的区域,我的拖放function就完美了。 但是,如果放在其他地方,我不会得到一个事件,并且在失败的拖放操作之后无法清理。 我需要触发ACTION_DRAG_ENDED事件。 但是,如果我回应ACTION_DRAG_STARTED的值为true(意味着它可以接受对象),则只会触发(根据文档)。 问题是ACTION_DRAG_STARTED不是射击!

所以我认为问题的症结在于我没有获得ACTION_DRAG_STARTED。 我在这里把所有相关的拖放代码(或者至less几乎所有的)

private OnTouchListener onTouchListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Item current = (Item) ((View) v.getTag()).getTag(); //ClipData data = ClipData.newPlainText("test", "testText"); View dragView = (View) v.getTag(); DragShadowBuilder shadowBuilder = new ItemDragShadowBuilder(dragView, new Point(v.getWidth()/2, v.getHeight()/2)); dragSource = dragView; v.startDrag(null, shadowBuilder, current, 0); dragView.setVisibility(View.INVISIBLE); return true; } else { return false; } } }; private static class ItemDragShadowBuilder extends View.DragShadowBuilder { private Point touchPoint = null; private Point sizePoint = null; private View dragView = null; public ItemDragShadowBuilder(View dragView, Point touchPoint) { super(); sizePoint = new Point(dragView.getWidth(), dragView.getHeight()); this.touchPoint = touchPoint; this.dragView = dragView; } @Override public void onProvideShadowMetrics (Point size, Point touch) { size.set(sizePoint.x, sizePoint.y); touch.set(touchPoint.x,touchPoint.y); } @Override public void onDrawShadow(Canvas canvas) { dragView.setBackgroundColor(dragView.getContext().getResources().getColor(R.color.holoBlueDark)); dragView.draw(canvas); //canvas.setBitmap(dragView.getDrawingCache()); //canvas.drawColor(Color.WHITE); //dragView.setAlpha(1); //How do I change the transparency? //super.onDrawShadow(canvas); } } private View dragSource = null; private OnDragListener onDragEventListener = new OnDragListener() { @Override public boolean onDrag(View v, DragEvent event) { final int action = event.getAction(); switch (action) { case DragEvent.ACTION_DRAG_STARTED: Toast.makeText(v.getContext(), ((EditText) v.findViewById(R.id.edtParent)).getText().toString() + " started", Toast.LENGTH_SHORT/8).show(); return true; //break;//DRAG AND DROP>>>START DOESN"T FIRE case DragEvent.ACTION_DROP: if ((dragSource != null) && (dragSource != v)) { Item source = (Item) dragSource.getTag(); Item target = (Item) v.getTag(); int sourcePos = source.getPosition(); int targetPos = target.getPosition(); if (targetPos < sourcePos) source.moveUp(sourcePos - targetPos); else source.moveDown(targetPos - sourcePos); dragSource.setVisibility(View.VISIBLE); dragSource = null; fireOnChecklistNeedsResetListener(); return true; } // View view = (View) event.getLocalState(); // Toast.makeText(v.getContext(), ((EditText) v.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show(); // Toast.makeText(v.getContext(), ((EditText) view.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show(); // Dropped, reassign View to ViewGroup // View view = (View) event.getLocalState(); // ViewGroup owner = (ViewGroup) view.getParent(); // owner.removeView(view); // LinearLayout container = (LinearLayout) v; // container.addView(view); // view.setVisibility(View.VISIBLE); break; case DragEvent.ACTION_DRAG_ENDED: dragSource.setVisibility(View.VISIBLE); dragSource = null; fireOnChecklistNeedsResetListener(); if (!event.getResult()) Toast.makeText(v.getContext(), "UNHANDLED", Toast.LENGTH_SHORT/8).show(); // View vieww = (View) event.getLocalState(); // Toast.makeText(v.getContext(), ((EditText) v.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show(); // Toast.makeText(v.getContext(), ((EditText) vieww.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show(); break; case DragEvent.ACTION_DRAG_ENTERED: v.setBackgroundColor(v.getContext().getResources().getColor(R.color.holoBlueLight)); return true; //break; case DragEvent.ACTION_DRAG_EXITED: v.setBackgroundColor(v.getContext().getResources().getColor(android.R.color.background_light)); return false; //break; default: break; } return false; } }; 

扩展信息:dragView是一个列表视图中的项目布局(特别是一个expandablelistview)。 接受触摸事件的视图是小视图上的一个小字形,并具有小抓握。 这是一个正在进行拖动操作的屏幕截图(花了一些奇特的手指来获得这个笑声):

拖/放屏幕

所以,如果我把拖放的项目放在另一个项目(这重新sorting),它的效果很好。 如果我把它放在其他地方没有事件发生,所以我永远不能清理它。 因此,例如在屏幕的上半部分,或者如果列表在空白区域或在底部或任何系统区域的蓝色条短。

我也可以通过找出一种办法来防止拖出有效区域来解决这个问题,所以如果你知道如何做到这一点,那就是解决这个问题的另一种方法。 我的最后一个select是在屏幕上为每个可能的视图实现一个事件(同样,这些是列表视图布局,在一个片段上的列表视图布局,这可能是在各种活动),所以显然这是不可取的。 而事实上,如果我这样做,我仍然可能有一个问题,如果它是在系统UI区域(如系统或电容button区域),但我不知道。

在这里有帮助的地方是我在哪里分配相关的事件过程(我删除不相关的行)在列表视图中适配器获取视图项目的方法:

 public View getGroupEdit(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { if (convertView != null) { //irrelevant stuff omitted } else convertView = inf.inflate(R.layout.edit_group_item, null); Item group = (Item) getGroup(groupPosition); convertView.setTag(group); EditText edtParent = (EditText) convertView.findViewById(R.id.edtParent); edtParent.setTag(convertView); scatterItemText(edtParent); //irrelevant stuff omitted ImageView imgGrip = (ImageView) convertView.findViewById(R.id.imgGrip); imgGrip.setTag(convertView); //irrelevant stuff omitted imgGrip.setOnTouchListener(onTouchListener); convertView.setOnDragListener(onDragEventListener); return convertView; } 

最后是FWIW,这是列表项视图的布局XML:

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="55dip" android:orientation="horizontal" > <ImageView android:id="@+id/imgGrip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:src="@drawable/dark_grip2" android:contentDescription="@string/strReorder"/> <CheckBox android:id="@+id/chkParent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/imgGrip" android:checked="false"/> <EditText android:id="@+id/edtParent" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/chkParent" android:layout_toLeftOf="@+id/btnInsert" android:textSize="17dip" android:inputType="text" android:hint="@string/strItem"/> <ImageButton android:id="@id/btnInsert" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_toLeftOf="@+id/viewParent" android:src="@drawable/dark_content_new" android:clickable="true" android:hint="@string/strAddItemAbove" android:contentDescription="@string/strAddItemAbove" /> <View android:id="@id/viewParent" android:layout_height="match_parent" android:layout_width="0dp" android:layout_toLeftOf="@+id/btnExpand"/> <ImageButton android:id="@id/btnExpand" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_alignParentRight="true" android:src="@drawable/dark_add_sub_item" android:clickable="true" android:hint="@string/strViewSubItems" android:contentDescription="@string/strViewSubItems"/> </RelativeLayout> 

非常感谢您的帮助!

Solutions Collecting From Web of "Android的拖放操作ACTION_DRAG_ENDED不能触发"

需要通知拖动事件的视图必须注册OnDragListeners 。 如果他们需要知道具体的东西或types的东西移动,例如为了改变他们的外观(或者是“在这里拖着我!”或者“不要你丢弃我!”)。 即使您的视图不是放置被拖动对象的有效位置,但是如果需要“拖动上下文”,也就是说,它会注册一个OnDragListener并为ACTION_DRAG_STARTED返回true。

我从一个非常彻底的问题中所遗漏的一件事就是你需要清理的是什么? 如果您只需要在活动范围内执行一些通用的事情,则可以考虑将另一个OnDragListener添加到基本的RelativeLayout ,该基本的RelativeLayout注册了事件,但等待ACTION_DRAG_ENDED以提醒活动执行通用清理代码

这可能与这个问题有关:

https://code.google.com/p/android/issues/detail?id=25073

覆盖dispatchDragEvent函数build议在该链接为我工作:

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