查看拖放排序

我有一个列表视图中的记录列表,我希望用户能够使用拖放方法重新排序。我已经在其他应用程序中看到过这个实现,但是我还没有找到相关的教程。一定是别人也需要的东西。有人能告诉我怎么做吗?

108222 次浏览

我已经研究这个有一段时间了。很难做对,虽然我不认为我做对了,但目前为止我很满意。我的代码和几个演示可以在

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

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

我添加这个答案的目的是为了那些谁谷歌关于这个. 。

最近有一集 DevBytes (拖动和重新排列单元格)解释了如何做到这一点

你可以找到它的 给你也示例代码是可用的 给你

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

我发现 DragSortListView工作得很好,尽管开始使用它可能会更容易。下面是一个关于在 Android Studio 中使用内存列表的简短教程:

  1. 将这个添加到应用程序的 build.gradle依赖项中:

    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 ArrayAdapter derivative with a getView 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);
    
  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();
    }
    });
    

DragListView 库对自定义动画(比如海拔动画)提供了非常好的支持。该系统仍然定期维护和更新。

以下是使用方法:

1: 首先将 lib 添加到 gradle

dependencies {
compile 'com.github.woxthebox:draglistview:1.2.1'
}

从 xml 添加列表

<com.woxthebox.draglistview.DragListView
android:id="@+id/draglistview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

设置拖放监听器

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

实现一个从 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

现在用 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 找到: 使用回收视图进行拖动

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


基本上,它包括创建自定义 Adapter,将 ArrayAdapter扩展为包含 ListView的活动的内部类。然后在这个适配器上设置一个 onTouchListener到您的 List Items,它将发出拖动开始的信号。

在这个 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;
}
}

这还涉及到向 ListView添加一个 onTouchListener,它检查一个项是否正在被拖动,处理交换和失效,并停止拖动状态。这部分摘录如下:

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

我建立了一个新的图书馆的基础上回收视图,检查出来

为了完成这个任务,请检查我的新图书馆 Https://github.com/ueen/sortview/