Android 列表视图拖放排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2909311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android List View Drag and Drop sort
提问by miannelle
I have a list of records in a listview that I want the user to be able to re-sort using a drag and drop method. I have seen this implemented in other apps, but I have not found a tutorial for it. It must be something that others need as well. Can anyone point me to some code for doing this?
我在列表视图中有一个记录列表,我希望用户能够使用拖放方法重新排序。我已经在其他应用程序中看到了这个实现,但我还没有找到它的教程。它必须是其他人也需要的东西。任何人都可以指出我这样做的一些代码吗?
回答by heycosmo
I have been working on this for some time now. Tough to get right, and I don't claim I do, but I'm happy with it so far. My code and several demos can be found at
我已经为此工作了一段时间。很难做到正确,我并不声称我做到了,但到目前为止我很满意。我的代码和几个演示可以在
Its use is very similar to the TouchInterceptor (on which the code is based), although significantimplementation changes have been made.
它的使用与 TouchInterceptor(代码所基于的)非常相似,尽管已经进行了重大的实现更改。
DragSortListView has smooth and predictable scrolling while dragging and shuffling items. Item shuffles are much more consistent with the position of the dragging/floating item. Heterogeneous-height list items are supported. Drag-scrolling is customizable (I demonstrate rapid drag scrolling through a long list---not that an application comes to mind). Headers/Footers are respected. etc.?? Take a look.
DragSortListView 在拖动和调整项目时具有平滑且可预测的滚动。项目洗牌与拖动/浮动项目的位置更加一致。支持异构高度列表项。拖动滚动是可定制的(我演示了在一个长列表中快速拖动滚动——不是我想到的应用程序)。页眉/页脚受到尊重。等等。??看一看。
回答by birdy
Now it's pretty easy to implement for RecyclerView
with ItemTouchHelper. Just override onMove
method from ItemTouchHelper.Callback
:
现在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;
}
Pretty good tutorial on this can be found at medium.com : Drag and Swipe with RecyclerView
可以在 medium.com 上找到关于此的非常好的教程:使用 RecyclerView 拖动和滑动
回答by Arun C
Am adding this answer for the purpose of those who google about this..
我添加这个答案是为了那些在谷歌上搜索这个的人..
There was an episode of DevBytes (ListView Cell Dragging and Rearranging) recently which explains how to do this
最近有一集 DevBytes ( ListView CellDragging and Rearrangeing) 解释了如何做到这一点
You can find it herealso the sample code is available here.
What this code basically does is that it creates a dynamic listview
by the extension of listview
that supports cell dragging and swapping. So that you can use the DynamicListView
instead of your basic ListView
and that's it you have implemented a ListView with Drag and Drop.
这段代码的主要作用是创建一个支持单元格拖动和交换dynamic listview
的扩展名listview
。这样你就可以使用 DynamicListView
代替你的基本ListView
,就是这样,你已经通过拖放实现了一个 ListView。
回答by Wox
The DragListView lib does this really neat with very nice support for custom animations such as elevation animations. It is also still maintained and updated on a regular basis.
DragListView 库非常巧妙地支持自定义动画,例如高度动画。它仍然定期维护和更新。
Here is how you use it:
以下是您如何使用它:
1: Add the lib to gradle first
1:先将lib添加到gradle
dependencies {
compile 'com.github.woxthebox:draglistview:1.2.1'
}
2: Add list from xml
2:从xml添加列表
<com.woxthebox.draglistview.DragListView
android:id="@+id/draglistview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
3: Set the drag listener
3:设置拖动监听器
mDragListView.setDragListListener(new DragListView.DragListListener() {
@Override
public void onItemDragStarted(int position) {
}
@Override
public void onItemDragEnded(int fromPosition, int toPosition) {
}
});
4: Create an adapter overridden from DragItemAdapter
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: Implement a viewholder that extends from DragItemAdapter.ViewHolder
5:实现一个从 DragItemAdapter.ViewHolder 扩展的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;
}
}
For more detailed info go to https://github.com/woxblom/DragListView
有关更多详细信息,请访问https://github.com/woxblom/DragListView
回答by Edward Brey
I found DragSortListViewworked well, although getting started on it could have been easier. Here's a brief tutorial on using it in Android Studio with an in-memory list:
我发现DragSortListView运行良好,尽管开始使用它可能更容易。这是一个关于在 Android Studio 中使用内存列表的简短教程:
Add this to the
build.gradle
dependencies for your app:compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
Create a resource for the drag handle ID by creating or adding to
values/ids.xml
:<resources> ... possibly other resources ... <item type="id" name="drag_handle" /> </resources>
Create a layout for a list item that includes your favorite drag handle image, and assign its ID to the ID you created in step 2 (e.g.
drag_handle
).Create a DragSortListView layout, something like this:
<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"/>
Set an
ArrayAdapter
derivative with agetView
override that renders your list item view.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);
Set a drop listener that rearranges the items as they are dropped.
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(); } });
将此添加到
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(); } });
回答by DarkCygnus
I recently stumbled upon this great Gistthat gives a working implementation of a drag sort ListView
, with no external dependencies needed.
我最近偶然发现了这个伟大的Gist,它提供了一个拖动排序的工作实现ListView
,不需要外部依赖。
Basically it consists on creating your custom Adapter extending ArrayAdapter
as an inner class to the activity containing your ListView
. On this adapter one then sets an onTouchListener
to your List Items that will signal the start of the drag.
基本上它包括创建您的自定义适配器ArrayAdapter
作为内部类扩展到包含您的ListView
. 在此适配器上,然后onTouchListener
为您的列表项设置一个,这将表示拖动的开始。
In that Gist they set the listener to a specific part of the layout of the List Item (the "handle" of the item), so one does not accidentally move it by pressing any part of it. Personally, I preferred to go with an onLongClickListener
instead, but that is up to you to decide. Here an excerpt of that part:
在那个 Gist 中,他们将侦听器设置为 List Item 布局的特定部分(项目的“句柄”),因此人们不会通过按下它的任何部分来意外移动它。就个人而言,我更喜欢使用 anonLongClickListener
代替,但这取决于您的决定。这是该部分的摘录:
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;
}
}
This also involves adding an onTouchListener
to the ListView
, which checks if an item is being dragged, handles the swapping and invalidation, and stops the drag state. An excerpt of that part:
这也包括添加一个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;
}
});
Finally, here is how the stopDrag
and startDrag
methods look like, which handle the enabling and disabling of the drag process:
最后,这里是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();
}