目的
Android 3.0 のドラッグ アンド ドロップ フレームワークに従って、「ListView からアイテムを並べ替える」パラダイムを実装しました。
問題
Android 4.0.3 および 4.0.4 で見られます。他のリリースではテストされていません。
ListView の項目をドラッグし、ListView の最後の項目の後にドロップします。シャドー ボックスがクリアされ、ListView が無効になります。これは通常の動作であり、90% の確率で発生します。
しかし、残りの 10% については、次のようになります。
- 注
onDrag(View, DragEvent)
: 以下にリストされているすべての効果は、が に戻った後に見られACTION_DRAG_ENDED
ます。つまり、問題が発生する前に、ドラッグ アンド ドロップ プロセス全体が完了しているように見えます。 - シャドー ボックスが表示されるのは、消える前にわずか 10 秒です。ハンドラー forを呼び出す
view.invalidate()
と、それは修正されますが、ハングまたは再起動の問題は修正されません (以下を参照)。onDrag(View, DragEvent)
ACTION_DRAG_ENDED
- logcat のいくつかの異常なトレース:
I/ViewRootImpl( 954): レポート ドロップ結果: true I/InputQueue-JNI( 210): 入力メッセージがまだ進行中に登録解除されているため、入力チャネル 'ドラッグ (クライアント)' の完了信号を送信しています。I/InputQueue-JNI( 210): 登録されなくなったチャネルの終了信号を無視します。W/WindowManager( 210): ドラッグは進行中ですが、ドラッグ ウィンドウ ハンドルがありません。I/ViewRootImpl( 954): レポート ドロップ結果: true
- 一部のデバイスでは、Android がハングまたは再起動します。デバイスによって異なりますが、効果は常に同じです。
ソースコード
import android.annotation.SuppressLint;
import android.app.ListActivity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class TestReorderActivity extends ListActivity {
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView listView = getListView();
String[] listeStrings = { "France", "United States", "Russia" };
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, listeStrings));
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapter, View view,
int id, long position) {
ClipData data = ClipData.newPlainText(" ",
Long.toString(position));
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
view);
if (view.startDrag(data, shadowBuilder/*
* new
* MyDragShadowBuilder(view)
*/, view, 0)) {
return true;
}
return false;
}
});
listView.setOnDragListener(new ListView.OnDragListener() {
@Override
public boolean onDrag(View view, DragEvent event) {
final int action = event.getAction();
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
if (event.getClipDescription().hasMimeType(
ClipDescription.MIMETYPE_TEXT_PLAIN)) {
// accept drag
return true;
} else {
// reject drag
return false;
}
case DragEvent.ACTION_DRAG_ENTERED:
// entered drag
return true;
case DragEvent.ACTION_DRAG_LOCATION:
// location is returned as event.getX() and event.getY()
return true;
case DragEvent.ACTION_DRAG_EXITED:
// cancel drag.
return true;
case DragEvent.ACTION_DROP:
// item dropped
processDrop(event);
return true;
case DragEvent.ACTION_DRAG_ENDED:
default: // unknown case
return true;
}
}
private boolean processDrop(DragEvent event) {
ClipData data = event.getClipData();
if ((data != null) && (data.getItemCount() > 0)) {
ClipData.Item item = data.getItemAt(0);
CharSequence value = item.getText();
long position = Long.valueOf(value.toString());
int x = (int) event.getX();
int y = (int) event.getY();
ListView listView = getListView();
int newPosition = listView.pointToPosition(x, y);
if (newPosition > ListView.INVALID_POSITION) {
swap(position, newPosition);
return true;
}
}
return false;
}
});
}
// swap(long, long) here
}