Android では、ListView
ドラッグ アンド ドロップを使用してアイテムを並べ替えられるようにしたいと考えています。「ドラッグ アンド ドロップ リストビュー」にはさまざまな実装があることは知っていますが、 API レベル 11以降のドラッグ アンド ドロップ フレームワークを使用したいと考えています。
ListView
ドラッグアンドドロップをしながらスクロールしたくなるまで、それは非常にうまく始まりました。下の例に書いてあるように、とりあえずどのリスト要素の上にいるのかを確認するので、その位置が間ListView.getLastVisiblePosition()
にない場合ListView.getFirstVisiblePosition()
は a を使っListView.smoothScrollToPosition()
て他のリスト項目を表示します。
初めての実装ですが、かなりうまく機能しています。
スクロール中に問題が発生します。一部の要素は、ドラッグ アンド ドロップ イベントに応答しません。他の要素はDragEvent.ACTION_DRAG_ENTERED
、それらの上にいるときに応答しません。これは、ListView がアイテム ビューを管理する方法によるものです。表示されなくなったアイテム ビューをリサイクルしようとします。
問題なく動作getView()
しListAdapter
ますが、 の が新しいオブジェクトを返す場合があります。このオブジェクトは新しいため、他のイベントDragEvent.ACTION_DRAG_STARTED
に応答しません。DragEvent
ここに例があります。この場合、リスト アイテムを長押ししてドラッグ アンド ドロップを開始し、それをドラッグすると、アイテムの上にいる場合、ほとんどのアイテムの背景が緑色になります。しかし、そうでない人もいます。
見逃した場合でも、ドラッグ アンド ドロップ イベント メカニズムにサブスクライブさせることについて何か考えはありDragEvent.ACTION_DRAG_STARTED
ますか?
// Somewhere I have a ListView that use the MyViewAdapter
// MyListView _myListView = ...
// _myListView.setAdapter(new MyViewAdapter(getActivity(), ...));
_myListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(null, shadowBuilder, _myListView.getItemAtPosition(position), 0);
return true;
}
});
class MyViewAdapter extends ArrayAdapter<MyElement> {
public MyViewAdapter(Context context, List<TimedElement> objects) {
super(context, 0, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View myElementView = convertView;
if (myElementView == null) {
/* If the code is executed here while scrolling with a drag and drop,
* the new view is not associated to the current drag and drop events */
Log.d("app", "Object created!");
// Create view
// myElementView = ...
// Prepare drag and drop
myElementView.setOnDragListener(new MyElementDragListener());
}
// Associates view and position in ListAdapter, needed for drag and drop
myElementView.setTag(R.id.item_position, position);
// Continue to prepare view
// ...
return timedElementView;
}
private class MyElementDragListener implements View.OnDragListener {
@Override
public boolean onDrag(View v, DragEvent event) {
final int action = event.getAction();
switch(action) {
case DragEvent.ACTION_DRAG_STARTED:
return true;
case DragEvent.ACTION_DRAG_ENTERED:
v.setBackgroundColor(Color.GREEN);
v.invalidate();
return true;
case DragEvent.ACTION_DRAG_LOCATION:
int targetPosition = (Integer)v.getTag(R.id.item_position);
if (event.getY() < v.getHeight()/2 ) {
Log.i("app", "top "+targetPosition);
}
else {
Log.i("app", "bottom "+targetPosition);
}
// To scroll in ListView while doing drag and drop
if (targetPosition > _myListView.getLastVisiblePosition()-2) {
_myListView.smoothScrollToPosition(targetPosition+2);
}
else if (targetPosition < _myListView.getFirstVisiblePosition()+2) {
_myListView.smoothScrollToPosition(targetPosition-2);
}
return true;
case DragEvent.ACTION_DRAG_EXITED:
v.setBackgroundColor(Color.BLUE);
v.invalidate();
return true;
case DragEvent.ACTION_DROP:
case DragEvent.ACTION_DRAG_ENDED:
default:
break;
}
return false;
}
}
}