Android列表视图拖放排序

Posted

技术标签:

【中文标题】Android列表视图拖放排序【英文标题】:Android List View Drag and Drop sort 【发布时间】:2011-02-23 22:58:14 【问题描述】:

我在列表视图中有一个记录列表,我希望用户能够使用拖放方法重新排序。我已经在其他应用程序中看到了这一点,但我还没有找到它的教程。它必须是其他人也需要的东西。任何人都可以指出一些代码来执行此操作吗?

【问题讨论】:

我发现这个教程可能对making a sortable list view有帮助。我还没有测试过,但视频看起来很有希望 @Arkde 不开玩笑,多年后他们仍然没有接受这个问题的答案。 @ArtOfWarfare 我想人们应该考虑到提问者可能发生了不幸的事情......不允许进一步的活动。 @heycosmo 有可能...根据他们的 SO 简介,miannelle 在提出问题后仅一个月就访问了。此外,在 DSLV 上做得很好......我对其进行了一些修改,以允许双击复制项目并在拖动项目时更改项目的阴影(我的项目每个都有它们的行号,所以我这样做是为了让行号更新可以在拖动时更新。)它们只是被黑了,远不如课堂上的其他东西优雅,因此我没有将更改提交到 GitHub。 github.com/bauerca/drag-sort-listview 我正在使用它,是否可以在 Listview 的LongClick 上拖动 ROW ? 【参考方案1】:

我已经为此工作了一段时间。很难做到正确,我并没有声称我做到了,但到目前为止我对此感到满意。我的代码和几个演示可以在

找到 https://github.com/bauerca/drag-sort-listview

它的使用与 TouchInterceptor(代码所基于的)非常相似,尽管已经对实现进行了重大更改。

DragSortListView 在拖动和随机播放项目时具有平滑且可预测的滚动。项目随机播放与拖动/浮动项目的位置更加一致。支持异构高度列表项。拖动滚动是可定制的(我通过一个长列表演示了快速拖动滚动——而不是想到一个应用程序)。页眉/页脚受到尊重。等等。??看看吧。

【讨论】:

您的解决方案就像一个魅力。比其他人好多了。您的源代码的许可证是什么?阿帕奇 2.0? @heycosmo 我在使用演示中提供的视图在我的应用程序中创建布局时遇到了一些问题。几个命名空间错误,能否请您写一篇关于如何使用您提供的代码的小博文? 是否有可能修改代码,以便在您将项目拖到它们上方时不仅对项目进行排序吗? @heycosmo 你能让你的 GitHub 存储库可访问吗?好像下线了…… 不再维护 bauerca 存储库。这个分叉比较活跃:github.com/JayH5/drag-sort-listview【参考方案2】:

现在很容易用ItemTouchHelper 实现RecyclerView。只需覆盖 ItemTouchHelper.Callback 中的 onMove 方法即可:

 @Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) 
    mMovieAdapter.swap(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    return true;

可以在 medium.com 找到很好的教程:Drag and Swipe with RecyclerView

【讨论】:

【参考方案3】:

我添加这个答案是为了那些在谷歌上搜索的人。

最近有一集 DevBytes (ListView Cell Dragging and Rearranging) 解释了如何做到这一点

你可以在here找到它,示例代码也可以在here找到。

这段代码的基本作用是通过扩展listview 创建一个dynamic listview,支持单元格拖动和交换。这样您就可以使用DynamicListView 而不是基本的ListView,就是这样,您已经实现了一个带有拖放功能的ListView。

【讨论】:

使用 DevBytes 实现时请记住,如果对象数组,您的适配器和 DynamicListView 必须共享同一个实例。否则执行将不起作用。这对于静态列表来说不是问题,但对于加载器来说可能是一个挑战 我在当前的 5.0 android 版本上尝试了该示例。它现在有一些问题...... @TCA 是的,我在 5.0 上也遇到了问题。请帮忙。【参考方案4】:

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_
    android:layout_/>

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 扩展而来的 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

【讨论】:

【参考方案5】:

我发现DragSortListView 运行良好,尽管开始使用它可能更容易。以下是在 Android Studio 中使用内存列表的简短教程:

    将此添加到您应用的 build.gradle 依赖项中:

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
    

    通过创建或添加values/ids.xml为拖动手柄ID创建资源:

    <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_
        android:layout_
        dslv:drag_handle_id="@id/drag_handle"
        dslv:float_background_color="@android:color/background_light"/>
    

    设置带有getView 覆盖的ArrayAdapter 派生类,以呈现您的列表项视图。

        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://***.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();
            
        );
    

【讨论】:

【参考方案6】:

我最近偶然发现了这个很棒的Gist,它提供了拖动排序ListView 的工作实现,不需要外部依赖。


基本上,它包括创建自定义适配器,将ArrayAdapter 作为内部类扩展到包含ListView 的活动。然后在此适配器上为您的列表项设置一个onTouchListener,这将表示拖动的开始。

在该要点中,他们将侦听器设置为列表项布局的特定部分(项目的“句柄”),因此人们不会通过按下它的任何部分而意外移动它。就个人而言,我更喜欢使用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;
    
);

最后,下面是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();

【讨论】:

虽然这似乎是最简单的实现之一,但它看起来很糟糕(行只是切换,实际上看起来为零),感觉很糟糕,并且滚动浏览一个不适合屏幕的列表不可能(我经常切换行而不是滚动)。【参考方案7】:

我基于RecyclerView新建了一个库,看看

查看我的新库以执行此任务 https://github.com/ueen/SortView/

【讨论】:

以上是关于Android列表视图拖放排序的主要内容,如果未能解决你的问题,请参考以下文章

如何将下拉列表视图项目拖放到另一个列表视图

Table Dragger - 简单的 JS 拖放排序表格插件

markdown 拖放排序:设计与实现

将列表视图的列表项拖放到另一个列表视图列表项

理论 | HTML5 进阶系列:拖放 API 实现拖放排序

拖放到列表视图上,如何获取放置的项目位置