我正在尝试在android(冰淇淋三明治)中实现拖放ListView
。因此,当拖动的对象到达ListView
的边缘时,我在相关方向上滚动ListView
。问题是,当我们滚动时,有时适配器会根据需要创建新的View
,并且这些“新”View
之前没有收到ACTION_DRAG_STARTED
事件,因此不会收到DragEvent
{1}}更新。有什么方法可以将事件发送到这些视图吗?
答案 0 :(得分:1)
在listview中实现拖放的最简单方法是使用这个很棒的库。 https://github.com/commonsguy/cwac-touchlist 值得一试。
答案 1 :(得分:0)
查看View的来源,我看到了:
static final int DRAG_CAN_ACCEPT = 0x00000001;
int mPrivateFlags2;
boolean canAcceptDrag() {
return (mPrivateFlags2 & DRAG_CAN_ACCEPT) != 0;
}
mPrivateFlags2是包私有的,不会被SDK公开。但是,您应该能够通过执行以下操作在子类中更改它:
try {
Field mPrivateFlags2 = this.getClass().getField("mPrivateFlags2");
int currentValue = mPrivateFlags2.getInt(this);
mPrivateFlags2.setInt(this, currentValue | 0x00000001);
} catch (Exception e) {
}
答案 2 :(得分:0)
我有same problem。我没有解决这个回收问题,但我找到了一个可能的解决方法仍然使用Drag&删除框架。我们的想法是改变观点:不是在列表中的每个OnDragListener
上使用View
,而是可以直接在ListView
上使用。
然后我的想法是在做Drag&amp ;;时找到手指在哪个项目的顶部。删除,并在ListAdapter
的{{1}}中写入相关的显示代码。然后诀窍是找到我们所在的项目视图,以及放置的位置。
为了做到这一点,我将ListView
设置为适配器创建的每个视图id
位置 - ListView
,所以我可以稍后使用组合View.setId()
和ListView.pointToPosition()
。
作为一个拖动侦听器示例(我提醒您,应用于ListView.findViewById()
),它可能是这样的:
ListView
现在,如果您在执行拖放操作时需要获得视觉反馈,则有几种策略。例如,您可以在您的活动中有2个名为的实例变量:
// Initalize your ListView
private ListView _myListView = new ListView(getContext());
// Start drag when long click on a ListView item
_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;
}
});
// Set the adapter and drag listener
_myListView.setOnDragListener(new MyListViewDragListener());
_myListView.setAdapter(new MyViewAdapter(getActivity()));
// Classes used above
private class MyViewAdapter extends ArrayAdapter<Object> {
public MyViewAdapter (Context context, List<TimedElement> objects) {
super(context, 0, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View myView = convertView;
if (myView == null) {
// Instanciate your view
}
// Associates view and position in ListAdapter, needed for drag and drop
myView.setId(position);
return myView;
}
}
private class MyListViewDragListener 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_DROP:
// We drag the item on top of the one which is at itemPosition
int itemPosition = _myListView.pointToPosition((int)event.getX(), (int)event.getY());
// We can even get the view at itemPosition thanks to get/setid
View itemView = _myListView.findViewById(itemPosition );
/* If you try the same thing in ACTION_DRAG_LOCATION, itemView
* is sometimes null; if you need this view, just return if null.
* As the same event is then fired later, only process the event
* when itemView is not null.
* It can be more problematic in ACTION_DRAG_DROP but for now
* I never had itemView null in this event. */
// Handle the drop as you like
return true;
}
}
}
在private boolean ongoingDrag = false; // To know if we are in a drag&drop state
private int dragPosition = 0; // You put the itemPosition variable here
中执行拖放操作时,您可以修改这些变量,并在MyListViewDragListener
中使用它们的状态。当然不要忘记使用MyViewAdapter
或_myListView.getAdapter()).notifyDataSetChanged()
方法更新UI(在事件线程中,使用Handler)。
答案 3 :(得分:0)
问题是因为如果视图在调用时不可见,则listView.getPositionForView(view)返回-1。因此,滚动列表时依赖于此将失败。因此,您可以在列表项上设置listView.setOnItemLongClickListener(),而不是设置view.setOnLongClickListener(),该列表项调用项目上的startDrag()。 onItemLongClick()为您提供了可以在startDrag()的myLocalState参数中传递的位置。然后使用event.getLocalState()在onDrag()中恢复它并将其转换为Integer。像这样......
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
position -= listView.getHeaderViewsCount();
DragShadowBuilder dragShadow = new View.DragShadowBuilder(view);
view.startDrag(null, dragShadow, position, 0);
return true;
}
});
然后在你的OnDragListener ......
@Override
public boolean onDrag(View eventView, DragEvent event) {
Integer dragViewPos = ((Integer) event.getLocalState());
int eventViewPos = listView.getPositionForView(eventView) - listView.getHeaderViewsCount();
...
}