在RecyclerView拖放项目进行GridLayoutManager [英] Drag and drop items in RecyclerView with GridLayoutManager

查看:1046
本文介绍了在RecyclerView拖放项目进行GridLayoutManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现什么: 有GridLayoutManager一个RecyclerView支持拖放和重新排列物品的同时拖动。

边注:第一次发展与拖放任何

有很多关于如何使用ListView控件,例如用于实现该功能的主题:<一href="https://raw.githubusercontent.com/btownrippleman/FurthestProgress/master/FurthestProgress/src/com/anappforthat/android/languagelineup/DynamicListView.java" rel="nofollow">https://raw.githubusercontent.com/btownrippleman/FurthestProgress/master/FurthestProgress/src/com/anappforthat/android/languagelineup/DynamicListView.java

不过的例子都是平时很多code搭配,创造拖累看法位图和感觉它应该是可以实现使用相同的结果 View.startDrag(... )和RecyclerView与 notifyItemAdded() notifyItemMoved() notifyItemRemoved(),因为它们提供了重新排列动画。

于是我打了周围的一些,并提出了这一点:

 最后CardAdapter适配器=新CardAdapter(名单);
        adapter.setHasStableIds(真正的);
        adapter.setListener(新CardAdapter.OnLongClickListener(){
            @覆盖
            公共无效onLongClick(查看视图){

                ClipData数据= ClipData.newPlainText(,);
                View.DragShadowBuilder建设者=新View.DragShadowBuilder(视图);
                最终诠释POS = mRecyclerView.getChildAdapterPosition(视图);
                最终的目标项目= list.remove(POS);

                mRecyclerView.setOnDragListener(新View.OnDragListener(){

                    INT prevPos = POS机;

                    @覆盖
                    公共ondrag当布尔(视图中查看,的dragEvent的dragEvent){

                        最终诠释行动= dragEvent.getAction();
                        开关(动作){
                            案例DragEvent.ACTION_DRAG_LOCATION:
                                视图onTopOf = mRecyclerView.findChildViewUnder(dragEvent.getX(),dragEvent.getY());
                                INT I = mRecyclerView.getChildAdapterPosition(onTopOf);

                                list.add(我,list.remove(prevPos));
                                adapter.notifyItemMoved(prevPos,我);
                                prevPos =我;

                                打破;
                            案例DragEvent.ACTION_DROP:
                                视图underView = mRecyclerView.findChildViewUnder(dragEvent.getX(),dragEvent.getY());
                                INT underPos = mRecyclerView.getChildAdapterPosition(underView);

                                list.add(underPos,项目);
                                adapter.notifyItemInserted(underPos);
                                adapter.notifyDataSetChanged();
                                打破;
                        }

                        返回true;
                    }
                });

                view.startDrag(数据,生成器,查看,0);
            }
        });
        mRecyclerView.setAdapter(适配器);
 

这一块code的工作排序,我得到的交换,但很不稳定/不稳定的,有时当它刷新整个网格重新安排回原来的顺序或随机的东西。但无论如何,code以上仅仅是我的第一次快速的尝试,什么我真的更想知道的是,如果有这样的阻力一些标准/最佳实践方式,并放弃与ReyclerView的,或者解决的正确方式,它仍然是这就是被用于列表视图多年的一样吗?

解决方案

其实是有一个更好的方式来实现这一目标。你可以使用一些 RecyclerView 的伴侣类:

ItemTouchHelper ,这是

  

一个工具类中添加刷卡解雇和拖曳放大器;下降支持RecyclerView。

和<一href="https://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.Callback.html"相对=nofollow> ItemTouchHelper.Callback ,这是

  

ItemTouchHelper和应用程序之间的合约

  //创建一个`ItemTouchHelper`并将其连接到`RecyclerView`
ItemTouchHelper第i =新ItemTouchHelper(_ithCallback);
ith.attachToRecyclerView(RV);

//扩展回调类
ItemTouchHelper.Callback _ithCallback =新ItemTouchHelper.Callback(){
    //并在您的imlpementaion
    公共布尔onMove(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder,RecyclerView.ViewHolder目标){
        //获取viewHolder的和目标的位置在适配器的数据,交换他们
        Collections.swap(/ * RecyclerView.Adapter的数据收集* /,viewHolder.getAdapterPosition(),target.getAdapterPosition());
        //并通知其数据集已更改适配器
        _adapter.notifyItemMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition());
        返回true;
    }

    @覆盖
    公共无效onSwiped(RecyclerView.ViewHolder viewHolder,INT方向){
        //去做
    }

    //定义每种状态下启用的移动方向(空闲,刷卡,拖)。
    @覆盖
    公众诠释getMovementFlags(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder){
        返回makeFlag(ItemTouchHelper.ACTION_STATE_DRAG,
                ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.START | ItemTouchHelper.END);
    }
};
 

详情查看他们的文档。

What I want to achieve: Have a RecyclerView with GridLayoutManager that supports drag'n'drop and that rearranges the items while dragging.

Side note: First time developing anything with drag and drop.

There are a lot of topics on how to achieve this feature using a ListView, for example: https://raw.githubusercontent.com/btownrippleman/FurthestProgress/master/FurthestProgress/src/com/anappforthat/android/languagelineup/DynamicListView.java

However the examples are usually a lot of code with, creating bitmaps of the dragged view and it feels like it should be possible to achieve the same result using View.startDrag(...) and RecyclerView with notifyItemAdded(), notifyItemMoved() and notifyItemRemoved() since they provide rearrange animations.

So I played around some and came up with this:

final CardAdapter adapter = new CardAdapter(list);
        adapter.setHasStableIds(true);
        adapter.setListener(new CardAdapter.OnLongClickListener() {
            @Override
            public void onLongClick(View view) {

                ClipData data = ClipData.newPlainText("","");
                View.DragShadowBuilder builder = new View.DragShadowBuilder(view);
                final int pos = mRecyclerView.getChildAdapterPosition(view);
                final Goal item = list.remove(pos);

                mRecyclerView.setOnDragListener(new View.OnDragListener() {

                    int prevPos = pos;

                    @Override
                    public boolean onDrag(View view, DragEvent dragEvent) {

                        final int action = dragEvent.getAction();
                        switch(action) {
                            case DragEvent.ACTION_DRAG_LOCATION:
                                View onTopOf = mRecyclerView.findChildViewUnder(dragEvent.getX(), dragEvent.getY());
                                int i = mRecyclerView.getChildAdapterPosition(onTopOf);

                                list.add(i, list.remove(prevPos));
                                adapter.notifyItemMoved(prevPos, i);
                                prevPos = i;

                                break;
                            case DragEvent.ACTION_DROP:
                                View underView = mRecyclerView.findChildViewUnder(dragEvent.getX(), dragEvent.getY());
                                int underPos = mRecyclerView.getChildAdapterPosition(underView);

                                list.add(underPos, item);
                                adapter.notifyItemInserted(underPos);
                                adapter.notifyDataSetChanged();
                                break;
                        }

                        return true;
                    }
                });

                view.startDrag(data, builder, view, 0);
            }
        });
        mRecyclerView.setAdapter(adapter);

This piece of code sort of work, I get the swapping, but very unstable/shaky and sometimes when it's refreshing the whole grid is rearranged back to original order or to something random. Anyway the code above is just my first quick attempt, what I'm really more interested in knowing is if there's some standard/best practice way of doing the drag and drop with ReyclerView's or if the correct way of solving it is still the same that's been used for ListViews for years?

解决方案

There is actually a better way to achieve this. You can use some of the RecyclerView's "companion" classes:

ItemTouchHelper, which is

a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

and its ItemTouchHelper.Callback, which is

the contract between ItemTouchHelper and your application

// Create an `ItemTouchHelper` and attach it to the `RecyclerView`
ItemTouchHelper ith = new ItemTouchHelper(_ithCallback);
ith.attachToRecyclerView(rv);

// Extend the Callback class
ItemTouchHelper.Callback _ithCallback = new ItemTouchHelper.Callback() {
    //and in your imlpementaion of
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        // get the viewHolder's and target's positions in your adapter data, swap them
        Collections.swap(/*RecyclerView.Adapter's data collection*/, viewHolder.getAdapterPosition(), target.getAdapterPosition());
        // and notify the adapter that its dataset has changed
        _adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        //TODO    
    }

    //defines the enabled move directions in each state (idle, swiping, dragging). 
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        return makeFlag(ItemTouchHelper.ACTION_STATE_DRAG,
                ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.START | ItemTouchHelper.END);
    }
};

For more details check their documentation.

这篇关于在RecyclerView拖放项目进行GridLayoutManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆