RecyclerView滑动删除和拖动排序

转载:http://www.cnblogs.com/Fndroid/p/5657342.html


先看本篇内容的效果图:

效果内容主要有三部分:

  • 长按点击其中一个Item之后可以将其拖动到其他地方
  • 向左右滑动可以删除某个Item
  • 长按的时候会有一个浮起的动作,放下之后会重新重新对齐

 

①先易后难,卡片浮起效果 

在Material Design中,物件的呈现是以3d的模式来进行的,也就是在原来的基础上增加了一个Z轴来表示物体的高度。

 当我们点击一个卡片的时候,应该给予用户一些反馈,让用户知道自己在操作这个卡片,也就是触摸反馈。触摸效果图的触摸反馈是先出现水波纹,接着当卡片可以移动的时候先浮动,再开始移动,最后下落,效果如下:(浮起的动画可能要仔细看)

 

实现:

水波纹效果使用系统提供的,因为Demo中使用的是一个CardView来呈现内容,所以只需要给CardView加上两个属性即可:

android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"

 

浮起和下沉的动画也不难,改变View的translationZ属性即可:

复制代码
private void pickUpAnimation(View view) {
    ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationZ", 1f, 10f);
    animator.setInterpolator(new DecelerateInterpolator());
    animator.setDuration(300);
    animator.start();
}
复制代码

 

 

②滑动(Swipe)和移动(Move)Item

Swipe是指我们上面的左右滑动删除,Move则是我们对Item的移动,改变列表的排序。要实现这两个功能,需要用到一个类ItemTouchHelper,当我们构造好这个类之后,可以调用它的attachToRecyclerView方法将其绑定在某个RecyclerView中,当RecyclerView出现某些操作(滑动和移动)时,构造这个类的时候传入的回调类会回调相应的方法,我们在这些方法中对数据集进行操作即可。

new ItemTouchHelper(new ItemTouchHelper.Callback() {
    //省略代码
}).attachToRecyclerView(mRecyclerView);

 

接着就是重写接口Callback的方法了,这里需要重写的有几个,分别是:

  • isItemViewSwipeEnable : Item是否可以滑动
  • isLongPressDragEnable :Item是否可以长按 
  • getMovementFlags : 获取移动标志
  • onMove : 当一个Item被另外的Item替代时回调,也就是数据集的内容顺序改变
  • onMoved : 当onMove返回true的时候回调
  • onSwiped : 当某个Item被滑动离开屏幕之后回调
  • setSelectedChange : 某个Item被长按选中会被回调,当某个被长按移动的Item被释放时也调用
复制代码
new ItemTouchHelper(new ItemTouchHelper.Callback() {
    private RecyclerView.ViewHolder vh;

    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder
            viewHolder) {
        // 拖拽的标记,这里允许上下左右四个方向
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT |
                ItemTouchHelper.RIGHT;
        // 滑动的标记,这里允许左右滑动
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    /*
        这个方法会在某个Item被拖动和移动的时候回调,这里我们用来播放动画,当viewHolder不为空时为选中状态
        否则为释放状态
     */
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        super.onSelectedChanged(viewHolder, actionState);
        if (viewHolder != null) {
            vh = viewHolder;
            pickUpAnimation(viewHolder.itemView);
        } else {
            if (vh != null) {
                putDownAnimation(vh.itemView);
            }
        }
    }


    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                          RecyclerView.ViewHolder target) {
        // 移动时更改列表中对应的位置并返回true
        Collections.swap(newsList, viewHolder.getAdapterPosition(), target
                .getAdapterPosition());
        return true;
    }

    /*
        当onMove返回true时调用
     */
    @Override
    public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int
            fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
        super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
        // 移动完成后刷新列表
        mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), target
                .getAdapterPosition());
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        // 将数据集中的数据移除
        newsList.remove(viewHolder.getAdapterPosition());
        // 刷新列表
        mAdapter.notifyItemRemoved(viewHolder.getAdapterPosition());
    }
}).attachToRecyclerView(mRecyclerView);
复制代码

 

这里直接贴出代码,并做了注释,应该比较简单了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这种情况可以通过在PopupWindow的setOnTouchListener()中监听手势事件,判断手势方向,然后决定是否让RecyclerView或者PopupWindow处理手势事件。 具体实现可以按照以下步骤: 1. 在PopupWindow的构造函数中设置setTouchable(true)和setFocusable(true),使PopupWindow能够响应点击和触摸事件。 2. 在PopupWindow的setOnTouchListener()中监听手势事件,并根据手势方向来判断是否让RecyclerView或者PopupWindow处理手势事件。例如: ``` popupWindow.setOnTouchListener(new View.OnTouchListener() { private float mLastY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = event.getRawY(); break; case MotionEvent.ACTION_MOVE: float dy = event.getRawY() - mLastY; if (Math.abs(dy) > 10) { // 如果手指上下滑动距离大于10,则拦截事件,让RecyclerView处理滑动事件 recyclerView.onTouchEvent(event); return true; } break; } return false; } }); ``` 3. 在RecyclerView的OnTouchListener()中,判断是否在PopupWindow内部,并根据需要决定是否拦截事件。例如: ``` recyclerView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // 判断是否在PopupWindow内部 Rect rect = new Rect(); popupWindow.getContentView().getGlobalVisibleRect(rect); if (!rect.contains((int) event.getRawX(), (int) event.getRawY())) { // 如果不在PopupWindow内部,则让PopupWindow处理手势事件 popupWindow.onTouchEvent(event); return true; } return false; } }); ``` 通过这种方式,可以在PopupWindow中嵌套RecyclerView,并解决它们之间的手势冲突问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值