目的
我已经按照 Android 3.0 拖放框架实现了“从 ListView 重新排序项目”范例。
问题
在 android 4.0.3 和 4.0.4 上看到。未在其他版本上测试。
将 ListView 的一项拖放到 ListView 的最后一项之后。阴影框被清除并且 ListView 无效。这是名义上的行为,90% 的时间都会发生。
但对于剩下的 10%,会发生什么:
- 注意:下面列出的所有效果都是AFTER
onDrag(View, DragEvent)
has returned forACTION_DRAG_ENDED
,也就是说整个拖放过程似乎在问题发生之前就完成了。 - 阴影框在消失前仅显示 10 秒。调用处理程序将纠正
view.invalidate()
该问题,但不会解决挂起或重启问题(见下文)onDrag(View, DragEvent)
ACTION_DRAG_ENDED
- logcat 中的一些不寻常的痕迹:
I/ViewRootImpl(954):报告丢弃结果:真 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
}