• Android -- 实现RecyclerView可拖拽Item


    1,今天和大家一起实现RecyclerView可拖拽Item,主要是使用RecyclerView结合ItemTouchHelper来实现的,来看一下效果

     

    2,看一下怎么实现的呢,很简单,只需要给recyclerView添加一个ItemTouchHelper对象就行

    mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() );
    mItemTouchHelper.attachToRecyclerView(mRecyclerView);
    

     构造方法中需要一个CallBack对象,适用于拖拽或者剔除时的回调方法,所以我们主要是要重写CallBack中的相应方法,处理响应的逻辑

       首先来自定义一个CallBack类,继承与ItemTouchHepler.Callback()对象

                @Override
                public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                 
                }
    
                @Override
                public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                  
                  
                }
    
                @Override
                public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    
                }
    

      首先说一下getMovementFlags(),这个方法是设置是否滑动时间,以及拖拽的方向,所以在这里需要判断一下是列表布局还是网格布局,如果是列表布局的话则拖拽方向为DOWN和UP,如果是网格布局的话则是DOWN和UP和LEFT和RIGHT,对应这个方法的代码如下:

    @Override
                public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                    if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
                        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
                                ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                        final int swipeFlags = 0;
                        return makeMovementFlags(dragFlags, swipeFlags);
                    } else {
                        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                        final int swipeFlags = 0;
                        return makeMovementFlags(dragFlags, swipeFlags);
                    }
                }
    

      而onMove()方法则是我们在拖动的时候不断回调的方法,在这里我们需要将正在拖拽的item和集合的item进行交换元素,然后在通知适配器更新数据,也很简单,代码如下:

                @Override
                public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                    //得到当拖拽的viewHolder的Position
                    int fromPosition = viewHolder.getAdapterPosition();
                    //拿到当前拖拽到的item的viewHolder
                    int toPosition = target.getAdapterPosition();
                    if (fromPosition < toPosition) {
                        for (int i = fromPosition; i < toPosition; i++) {
                            Collections.swap(datas, i, i + 1);
                        }
                    } else {
                        for (int i = fromPosition; i > toPosition; i--) {
                            Collections.swap(datas, i, i - 1);
                        }
                    }
                    myAdapter.notifyItemMoved(fromPosition, toPosition);
                    return true;
                }
    

      onSwiped()是替换后调用的方法,可以不用管。然后我们希望在拖拽的时候将被拖拽的Item高亮,这样用户体验要好很多,所以我们要重写CallBack对象中的onSelectedChanged()和clearView()方法,在选中的时候设置高亮背景色,在完成的时候移除高亮背景色,代码如下:

                /**
                 * 长按选中Item的时候开始调用
                 *
                 * @param viewHolder
                 * @param actionState
                 */
                @Override
                public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
                    if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
                        viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
                    }
                    super.onSelectedChanged(viewHolder, actionState);
                }
    
                /**
                 * 手指松开的时候还原
                 * @param recyclerView
                 * @param viewHolder
                 */
                @Override
                public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                    super.clearView(recyclerView, viewHolder);
                    viewHolder.itemView.setBackgroundColor(0);
                }
    

      这样就实现了我们的基本要求,但是实际功能中有可能存在,排头前两个的不需改变它的顺序,即有些item允许拖拽,有些则不允许,所以我们需要重写isLongPressDragEnabled()设置不允许长按拖拽

                 /**
                 * 重写拖拽不可用
                 * @return
                 */
                @Override
                public boolean isLongPressDragEnabled() {
                    return false;
                }
    

      然后在重写RecycleView的长按监听(这个要自己写个接口去实现),在返回的长按方法中判断是否为不可拖拽的item,若不是,则调用ItemTouchHelper的startDrag()方法,逻辑出入如下:

               @Override
                public void onItemLongClick(RecyclerView.ViewHolder vh) {
                    //判断被拖拽的是否是前两个,如果不是则执行拖拽
                    if (vh.getLayoutPosition() != 0 && vh.getLayoutPosition() != 1) {
                        mItemTouchHelper.startDrag(vh);
    
                    }
                }
    

      为了功耗的用户体验 我们可以在长按的时候添加震动,添加权限

    <uses-permission android:name="android.permission.VIBRATE" />
    

      调用方法:

     //获取系统震动服务
     Vibrator vib = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
    //震动70毫秒
     vib.vibrate(70);
    

      这样功能就差不多实现了,这是GitHub下载链接  See You Next Time !

  • 相关阅读:
    面向对象的三个基本特征
    OGRE启动过程详解(OGRE HelloWorld程序原理解析)
    Bullet核心类介绍(Bullet 2.82 HelloWorld程序及其详解,附程序代码)
    windows下Bullet 2.82编译安装(Bullet Physics开发环境配置)
    1303: Decimal
    分组背包,每组最多选1个
    椒盐效果
    自我介绍
    题目1539:师弟
    upper_bound()
  • 原文地址:https://www.cnblogs.com/wjtaigwh/p/6543354.html
Copyright © 2020-2023  润新知