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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:50:46  来源:igfitidea点击:

Android List View Drag and Drop sort

androidlistview

提问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 RecyclerViewwith ItemTouchHelper. Just override onMovemethod 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 listviewby the extension of listviewthat supports cell dragging and swapping. So that you can use the DynamicListViewinstead of your basic ListViewand 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 中使用内存列表的简短教程:

  1. Add this to the build.gradledependencies for your app:

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
    
  2. 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>
    
  3. 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).

  4. 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"/>
    
  5. Set an ArrayAdapterderivative with a getViewoverride 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);
    
  6. 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();
            }
        });
    
  1. 将此添加到build.gradle您的应用程序的依赖项中:

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
    
  2. 通过创建或添加到 为拖动手柄 ID 创建资源values/ids.xml

    <resources>
        ... possibly other resources ...
        <item type="id" name="drag_handle" />
    </resources>
    
  3. 为包含您最喜欢的拖动手柄图像的列表项创建布局,并将其 ID 分配给您在步骤 2 中创建的 ID(例如drag_handle)。

  4. 创建一个 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"/>
    
  5. 设置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);
    
  6. 设置一个放置监听器,在放置时重新排列项目。

        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 ArrayAdapteras an inner class to the activity containing your ListView. On this adapter one then sets an onTouchListenerto 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 onLongClickListenerinstead, 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 onTouchListenerto 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:

这也包括添加一个onTouchListenerListView,它检查是否一个项目被拖动,把手的交换和无效,并停止拖动状态。该部分的摘录:

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 stopDragand startDragmethods look like, which handle the enabling and disabling of the drag process:

最后,这里是stopDragstartDrag方法的样子,它处理拖动过程的启用和禁用:

public void startDrag(String string) {
    mPosition = -1;
    mSortable = true;
    mDragString = string;
    mAdapter.notifyDataSetChanged();
}

public void stopDrag() {
    mPosition = -1;
    mSortable = false;
    mDragString = null;
    mAdapter.notifyDataSetChanged();
}