Android Drag and Drop ACTION_DRAG_ENDED не срабатывает

У меня действительно есть время понять это и не могу найти друзей с соответствующим опытом. Это моя ОЧЕНЬ ПОСЛЕДНЯЯ ХАРАКТЕРИСТИКА, прежде чем я выпущу свой ОЧЕНЬ ПЕРВЫЙ APP, так что это сводит меня с ума, чтобы увязнуть с ним с концом в поле зрения!

Моя перетаскивание отлично работает, если я отбрасываю объект в приемлемой области. Однако, если вы уронили в другое место, я не получаю событие и не могу выполнить очистку после неудачной операции перетаскивания. Мне нужно событие ACTION_DRAG_ENDED для запуска. Однако это только срабатывает (согласно документации), если я отвечу ACTION_DRAG_STARTED со значением true (что означает, что он может принять объект). Проблема ACTION_DRAG_STARTED не срабатывает!

Поэтому я считаю, что суть проблемы в том, что я не получаю ACTION_DRAG_STARTED. Я размещаю то, что должно быть всем соответствующим кодом dragdrop (или, по крайней мере, почти всем) здесь:

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 – это макет элемента в listview (в частности, расширенный список). Представление, которое принимает событие касания, представляет собой небольшой глиф на виде с небольшим захватом. Вот скриншот с текущей операцией перетаскивания (для получения этого LOL понадобилось несколько полезных действий):

Экран перетаскивания

Поэтому, если я должен был перетащить перетаскиваемый элемент на другой предмет (это переупорядочивает их), он отлично работает. Если я отброшу его в другое место, события не срабатывают, поэтому я никогда не смогу его очистить. Так, например, в верхней части экрана или если короткий список в пустой области или синяя полоска внизу или в любой из системных областей.

Я мог бы альтернативно решить эту проблему, выяснив способ предотвратить перетаскивание из допустимой области, поэтому, если вы знаете, как это сделать, это еще один способ ее решения. Моим последним вариантом было бы реализовать событие для каждого возможного представления на экране (опять же это макеты списка, в списке, который находится на фрагменте, который может быть на разных видах деятельности), поэтому, очевидно, это было бы нежелательно. И на самом деле, если я это сделаю, у меня все еще может возникнуть проблема, если он упадет в области пользовательского интерфейса системы (например, в системной панели или в области емкостных кнопок), но я не уверен.

В случае, если это полезно, здесь я назначаю соответствующие процедуры событий (я удаляю ненужные строки) в адаптерах просмотра списка. Метод просмотра:

 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> 

Большое спасибо за любую помощь!

Представления, которые должны быть уведомлены о событиях перетаскивания, должны регистрировать OnDragListeners . Если им нужно знать, когда движутся конкретные вещи или типы вещей, например, чтобы изменить их внешний вид (либо на «DRAG ME ЗДЕСЬ!», Либо «НЕ СДЕЛАЙТЕ УБЕДИТЕСЬ, ЧТО НА МЕНЯ!»). Даже если ваше представление не является допустимым местом для перетаскивания объекта, если он должен быть «перетаскивать контекст», так сказать, он регистрирует OnDragListener и возвращает true для ACTION_DRAG_STARTED .

Единственное, что мне не хватает из вашего очень тщательного вопроса, – именно то, что вам нужно очистить? Если вам просто нужно сделать некоторые общие вещи, которые входят в сферу действия, вы можете подумать о добавлении другого OnDragListener к базе RelativeLayout которая регистрирует события, но ждет ACTION_DRAG_ENDED чтобы предупредить активность о выполнении вашего общего кода очистки

Это может быть связано с этой проблемой:

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