我在列表视图中有一个记录列表,希望用户能够使用拖放方法进行重新排序。我已经在其他应用程序中实现了此功能,但没有找到相关的教程。这也必须是其他人也需要的。谁能指出我这样做的一些代码?
我在列表视图中有一个记录列表,希望用户能够使用拖放方法进行重新排序。我已经在其他应用程序中实现了此功能,但没有找到相关的教程。这也必须是其他人也需要的。谁能指出我这样做的一些代码?
Answers:
我已经为此工作了一段时间。很难做到正确,我并没有声称自己做到了,但是到目前为止我对此感到满意。我的代码和几个演示可以在以下位置找到
尽管已经进行了重大的更改,但它的用法与TouchInterceptor(代码所基于的)非常相似。
DragSortListView在拖动和拖移项目时具有平滑且可预测的滚动。项目混洗与拖动/浮动项目的位置更加一致。支持异构高度列表项。拖动滚动是可自定义的(我在很长的列表中演示了快速拖动滚动-并不是我想到的应用程序)。标头/页脚受到尊重。等等。??看一看。
现在,RecyclerView
使用ItemTouchHelper可以很容易实现。只是onMove
从重写方法ItemTouchHelper.Callback
:
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mMovieAdapter.swap(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
关于这个的很好的教程可以在medium.com上找到:使用RecyclerView拖动和滑动
正在添加此答案,以供那些对此进行谷歌搜索的人使用。
最近有一集DevBytes(ListView单元拖动和重新排列)说明了如何执行此操作
这段代码的基本作用是创建一个dynamic listview
扩展名,该扩展名listview
支持单元格拖动和交换。这样您就可以使用 DynamicListView
basic代替Basic了,ListView
并且已经实现了ListView的拖放操作。
DragListView库通过很好地支持自定义动画(例如高程动画)来做到这一点。它还会定期维护和更新。
使用方法如下:
1:首先将lib添加到gradle
dependencies {
compile 'com.github.woxthebox:draglistview:1.2.1'
}
2:从xml添加列表
<com.woxthebox.draglistview.DragListView
android:id="@+id/draglistview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
3:设置拖动侦听器
mDragListView.setDragListListener(new DragListView.DragListListener() {
@Override
public void onItemDragStarted(int position) {
}
@Override
public void onItemDragEnded(int fromPosition, int toPosition) {
}
});
4:创建从DragItemAdapter覆盖的适配器
public class ItemAdapter extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder>
public ItemAdapter(ArrayList<Pair<Long, String>> list, int layoutId, int grabHandleId, boolean dragOnLongPress) {
super(dragOnLongPress);
mLayoutId = layoutId;
mGrabHandleId = grabHandleId;
setHasStableIds(true);
setItemList(list);
}
5:实现一个从DragItemAdapter.ViewHolder扩展的视图持有者
public class ViewHolder extends DragItemAdapter.ViewHolder {
public TextView mText;
public ViewHolder(final View itemView) {
super(itemView, mGrabHandleId);
mText = (TextView) itemView.findViewById(R.id.text);
}
@Override
public void onItemClicked(View view) {
}
@Override
public boolean onItemLongClicked(View view) {
return true;
}
}
有关更多详细信息,请访问https://github.com/woxblom/DragListView
我发现DragSortListView运作良好,尽管开始使用它可能会更容易。这是有关在内存列表中在Android Studio中使用它的简短教程:
将此添加到build.gradle
您的应用程序的依赖项:
compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
通过创建或添加到来创建拖动手柄ID的资源values/ids.xml
:
<resources>
... possibly other resources ...
<item type="id" name="drag_handle" />
</resources>
为包含您喜欢的拖动手柄图像的列表项创建一个布局,然后将其ID分配给您在步骤2中创建的ID(例如drag_handle
)。
创建一个DragSortListView布局,如下所示:
<com.mobeta.android.dslv.DragSortListView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dslv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
dslv:drag_handle_id="@id/drag_handle"
dslv:float_background_color="@android:color/background_light"/>
设置带有ArrayAdapter
派生的派生类,以getView
呈现您的列表项视图。
final ArrayAdapter<MyItem> itemAdapter = new ArrayAdapter<MyItem>(this, R.layout.my_item, R.id.my_item_name, items) { // The third parameter works around ugly Android legacy. http://stackoverflow.com/a/18529511/145173
@Override public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
MyItem item = getItem(position);
((TextView) view.findViewById(R.id.my_item_name)).setText(item.getName());
// ... Fill in other views ...
return view;
}
};
dragSortListView.setAdapter(itemAdapter);
设置放置侦听器,以在放置物品时重新排列它们。
dragSortListView.setDropListener(new DragSortListView.DropListener() {
@Override public void drop(int from, int to) {
MyItem movedItem = items.get(from);
items.remove(from);
if (from > to) --from;
items.add(to, movedItem);
itemAdapter.notifyDataSetChanged();
}
});
我最近偶然发现了这个伟大的Gist,它提供了一种有效的拖动排序实现ListView
,而无需外部依赖。
基本上,它包括创建自定义Adapter ArrayAdapter
作为内部类扩展到包含的活动ListView
。然后在此适配器onTouchListener
上将一个设置为您的“列表项”,这将指示拖动开始。
在该Gist中,他们将侦听器设置为List Item布局的特定部分(该项目的“句柄”),因此不会意外按下它的任何部分来移动它。就我个人而言,我更喜欢选择一个onLongClickListener
,但是这取决于您自己决定。这是该部分的摘录:
public class MyArrayAdapter extends ArrayAdapter<String> {
private ArrayList<String> mStrings = new ArrayList<String>();
private LayoutInflater mInflater;
private int mLayout;
//constructor, clear, remove, add, insert...
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View view = convertView;
//inflate, etc...
final String string = mStrings.get(position);
holder.title.setText(string);
// Here the listener is set specifically to the handle of the layout
holder.handle.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
startDrag(string);
return true;
}
return false;
}
});
// change color on dragging item and other things...
return view;
}
}
这也包括添加一个onTouchListener
到ListView
,它检查是否一个项目被拖动,把手的交换和无效,并停止拖动状态。该部分的摘录:
mListView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
if (!mSortable) { return false; }
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
break;
}
case MotionEvent.ACTION_MOVE: {
// get positions
int position = mListView.pointToPosition((int) event.getX(),
(int) event.getY());
if (position < 0) {
break;
}
// check if it's time to swap
if (position != mPosition) {
mPosition = position;
mAdapter.remove(mDragString);
mAdapter.insert(mDragString, mPosition);
}
return true;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE: {
//stop drag state
stopDrag();
return true;
}
}
return false;
}
});
最后,这是stopDrag
和startDrag
方法的外观,它们处理启用和禁用拖动过程:
public void startDrag(String string) {
mPosition = -1;
mSortable = true;
mDragString = string;
mAdapter.notifyDataSetChanged();
}
public void stopDrag() {
mPosition = -1;
mSortable = false;
mDragString = null;
mAdapter.notifyDataSetChanged();
}