gpt4 book ai didi

android - 错过ACTION_DRAG_STARTED事件的拖放、ListView和itemView

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:51:29 25 4
gpt4 key购买 nike

在 Android 上,我使用 ListView 并且我希望能够使用拖放对其项目重新排序。我知道“拖放 ListView ”有不同的实现方式,但是我想使用 Drag and Drop frameworkAPI 级别 11 开始。

它开始非常好,直到我想在拖放时滚动我的 ListView。正如下面示例中所写,现在,我检查我在哪个列表元素之上,所以如果它的位置不在 ListView.getLastVisiblePosition()ListView.getFirstVisiblePosition( ) 我使用 ListView.smoothScrollToPosition() 来查看其他列表项。

这是第一个实现,但效果很好。

滚动时出现问题:某些元素不响应拖放事件 - DragEvent.ACTION_DRAG_ENTERED 和其他 - 当我在它们上面时。这是由于 ListView 管理其项目 View 的方式:它尝试回收不再可见的项目 View 。

一切正常并且可以正常工作,但有时 ListAdaptergetView() 会返回一个新对象。由于它是新对象,因此该对象错过了 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;
}
}
}

最佳答案

我没有解决这个回收问题,但我找到了一个可能的解决方法,仍然使用拖放框架。这个想法是改变视角:而不是使用 OnDragListener在每个 View在列表中,它可以用在 ListView 上直接。

然后思路就是在拖拽的时候找到手指在哪个item上面,把相关的显示代码写在ListAdapter中的 ListView .诀窍是找到我们所在的项目 View 的顶部,以及放置完成的位置。

为了做到这一点,我设置为 id对于适配器创建的每个 View 其 ListView位置 - 与 View.setId() ,所以我可以稍后使用 ListView.pointToPosition() 的组合找到它和 ListView.findViewById() .

作为拖动监听器示例(我提醒您,它应用于 ListView ),它可以是这样的:

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

关于android - 错过ACTION_DRAG_STARTED事件的拖放、ListView和itemView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14118984/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com