Android List View拖放排序


132

我在列表视图中有一个记录列表,希望用户能够使用拖放方法进行重新排序。我已经在其他应用程序中实现了此功能,但没有找到相关的教程。这也必须是其他人也需要的。谁能指出我这样做的一些代码?


1
我发现本教程可能有助于制作可排序的列表视图。我还没有测试过,但是视频看起来很有希望
Alex

@Arkde别开玩笑了,多年以后,他们仍然没有接受这个问题的答案。
ArtOfWarfare 2012年

@ArtOfWarfare我想应该考虑到不幸的事情可能发生在提问者身上……不允许进一步的活动。
heycosmo 2012年

1
@heycosmo可能...根据他们的SO档案,miannelle在问了问题仅一个月后上次访问。另外,在DSLV上的出色工作...我对其进行了一些修改,以允许双击双击重复的项目以及在拖动项目时更改项目的阴影(我的项目都有行号,所以我这样做是为了使行号更新可以在被拖动时进行更新。)它们只是被入侵,比类中的所有其他对象都优雅得多,因此为什么我没有将更改提交给GitHub。
ArtOfWarfare 2012年

github.com/bauerca/drag-sort-listview我正在使用它,是否可以在Listview上拖动ROW onLongClick?
阿钦(Achin)2015年

Answers:


85

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

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

DragSortListView在拖动和拖移项目时具有平滑且可预测的滚动。项目混洗与拖动/浮动项目的位置更加一致。支持异构高度列表项。拖动滚动是可自定义的(我在很长的列表中演示了快速拖动滚动-并不是我想到的应用程序)。标头/页脚受到尊重。等等。??看一看。


3
您的解决方案就像一个魅力。比别人好得多。您的源代码许可是什么?Apache 2.0?
Dariusz Bacinski

1
@heycosmo我使用演示中提供的视图在应用中创建布局时遇到一些问题。几个名称空间错误,您能否做一个关于如何使用您提供的代码的小博文?
daniel_c05

是否可以通过以下方式修改代码,即在将项目拖动到项目上方时,这些项目不仅按拖放方式进行排序?
Alex Semeniuk 2013年

@heycosmo您可以使您的GitHub存储库可访问吗?似乎已离线...
sdasdadas

8
鲍尔卡仓库已不再维护。这个分支更加活跃:github.com/JayH5/drag-sort-listview
ecdpalma

21

现在,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拖动和滑动


18

正在添加此答案,以供那些对此进行谷歌搜索的人使用。

最近有一集DevBytes(ListView单元拖动和重新排列)说明了如何执行此操作

您可以在这里找到它,示例代码也可以在这里找到

这段代码的基本作用是创建一个dynamic listview扩展名,该扩展名listview支持单元格拖动和交换。这样您就可以使用 DynamicListViewbasic代替Basic了,ListView 并且已经实现了ListView的拖放操作。


1
使用DevBytes实现时,请记住,如果对象数组,则适配器和DynamicListView必须共享同一实例。否则,实施将无法进行。对于静态列表而言,这不是问题,但对于装载机来说可能是个挑战
AAverin 2014年

我在当前的5.0 Android版本上尝试了该示例。现在有一些问题...
Torsten B

@TCA是的,我在5.0上也遇到了问题。请帮忙。
Manu 2015年

6

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


5

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

  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();
            }
        });
    

3

我最近偶然发现了这个伟大的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;
    }
}

这也包括添加一个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;
    }
});

最后,这是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();
}

尽管这似乎是最简单的实现之一,但它看起来很糟糕(行只是切换,实际上是零个外观),感觉很糟糕,并且使滚动浏览不适合屏幕的列表几乎是不可能的(我经常切换行而不是滚动)。
Heinzlmaen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.