RecyclerView交互动画

来源:互联网 发布:苏州爱知科技怎么样 编辑:程序博客网 时间:2024/06/05 07:02

一,我们先上效果图如下:
我们可以通过托拽让RecylerView的每个条目进行上下移动并调整位置。
这里写图片描述

二,分析如何做到:
之前写过一篇层叠卡片相册集,里面就用到了RecylerView一个拓展帮助类。谷歌在v7包中的这个帮助类ItemTouchHelper提供,它用来绑定RecylerView并且监听RecylerView内部的各种动作和行为,通过callBack回掉来处理RecylerView的滑动和拖拽行为和动作。
我们在MainActivity里面可以些出代码:

ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);itemTouchHelper.attachToRecyclerView(mRecylerView);

我们可以发现itemTouchHelper需要一个回掉类callback,我们来查看这个callback干嘛用的。我们点击源码可以看到在ItemTouchHelper内部有一个抽象静态内部类CallBack,通过源码注释

This class is the contract between ItemTouchHelper and your application. It lets you control* which touch behaviors are enabled per each ViewHolder and also receive callbacks when user* performs these actions.

我们可以知道这个类是帮助了和应用程序之间的合同,桥梁。它可以让用户界面接受回掉函数,来控制触摸行为和动作。接下来我们来自定义类并实现它。
代码如下:

public class ItemTouchHelperCallBack extends ItemTouchHelper.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) {    }    @Override    public boolean isLongPressDragEnabled() {        return true;    }}

我们继续看Callback的源码:分析每个方法干嘛用的:
首先是onMove()方法:
* Called when ItemTouchHelper wants to move the dragged item from its old position to
* the new position.
public abstract boolean onMove()可以看出这个方法用来给ItemTouchHelper回掉条目从原来位置移动到新位置。
然后是getMovementFlags方法
这个方法源码解释返回持有视图着拖动的方向。其实就是返回我们拖动item的方向。代码如下:
这里我们需要明白makeMovementFlags();这个方法是用来计算你手拖动和侧滑的方向。他会进行计算返回给你最终的方向值。我们这里先设置拖拽方向,侧滑方向就设为0,看看效果。

@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {   //这里是拖缀行为的方向。分为四个方向。我们设置为上下拖缀    int dragFlages = ItemTouchHelper.DOWN | ItemTouchHelper.UP;   //这里侧滑方向我们左右为0。不让左右不然滑动。    int swipFlags = 0;    int flages = makeMovementFlags(dragFlages, swipFlags);    return flages;}

目前整个代码如下:

public class ItemTouchHelperCallBack extends ItemTouchHelper.Callback {    @Override    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {        int dragFlages = ItemTouchHelper.DOWN | ItemTouchHelper.UP;        int swipFlags = 0;        int flages = makeMovementFlags(dragFlages, swipFlags);        return flages;    }   //当拖拽时候回掉的方法。    @Override    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {        return true;    }//当侧滑时候调用的方法。    @Override    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {    }    @Override    public boolean isLongPressDragEnabled() {        return true;    }}

然后我们在Activity中调用代码如下:

mRecylerView.setAdapter(mAdapter);mRecylerView.setLayoutManager(new LinearLayoutManager(this));ItemTouchHelper itemTouchHelper=new ItemTouchHelper(new ItemTouchHelperCallBack());itemTouchHelper.attachToRecyclerView(mRecylerView);

运行代码效果如下:
这里写图片描述

我们可以看出我们进行拖拽时候可以进行移动条目的位置。这里我们进行拖拽时候只有长安之后拖拽才会起作用。这样用户体验效果很差。有什么办法我们可以通过当按下头像就开始拖拽么?
我们可以发现ItemToucherHelper有一个方法,itemTouchHelper.startDrag(RecyclerView.ViewHolder);随时调用这个方法可以实现
拖拽动作。并且立即执行。那么我们如何可以在点击头像时候调用这个方法。接下来我们来实现这个代码:
我们在适配器中点击按下头像时候来进行接口回调在activity中实现调用。
首先来个接口实现回调。代码如下:

public interface StartDragListener {    public void StartDragListener(RecyclerView.ViewHolder viewHolder);}

我们在适配器里面点击这个头像时候监听触摸事件这里我们只需要判断按下时候进行接口回调,并且开启拖缀。代码如下:

holder.iv_logo.setOnTouchListener(new OnTouchListener() {   @Override   public boolean onTouch(View v, MotionEvent event) {      if(event.getAction()==MotionEvent.ACTION_DOWN){         startDragListener.StartDragListener(holder);         return true;      }      return false;   }});

这时候我们可以运行效果如下:
这里写图片描述

    我们可以看出我们进行拖拽时候可以进行移动条目的位置。这里我们进行拖拽时候只有长安之后拖拽才会起    作用。这样用户体验效果很差。有什么办法我们可以通过当按下头像就开始拖拽么?我们可以        ItemToucherHelper有一个方itemTouchHelper.startDrag(RecyclerView.ViewHolder);    下来我们来实现这个代码:我们在适配器中点击按下头像时候来进行接口回调在activity中实现调用。首    先来个接口实现回调。代码如下:
public interface StartDragListener {    public void StartDragListener(RecyclerView.ViewHolder viewHolder);}

我们在适配器里面点击这个头像时候监听触摸事件这里我们只需要判断按下时候进行接口回调,并且开启拖缀。代码如下:

holder.iv_logo.setOnTouchListener(new OnTouchListener() {   @Override   public boolean onTouch(View v, MotionEvent event) {      if(event.getAction()==MotionEvent.ACTION_DOWN){         startDragListener.StartDragListener(holder);         return true;      }      return false;   }});

这时候我们可以运行效果如下:
这里写图片描述

从最初的位置移动到目标位置。接下来我们来实现这个效果。 我之前一篇文章写过当关于添加数据到列表的item中,实现显示和更新。我们可以通过在适配器里面进行查看 到适配器有很多的方法例如:            * @see #notifyItemChanged(int)              @see #notifyItemInserted(int)            * @see #notifyItemRemoved(int)            * @see #notifyItemRangeChanged(int, int)            * @see #notifyItemRangeInserted(int, int)            * @see #notifyItemRangeRemoved(int, int)               源码知道:它是用来通知适配器条目从开始位置移动到目标位置。               所以我们可以通过这个方法进行条目的移动。

那问题来了什么时候进行位置的移动呢?当然是从我们拖拽开始到目标位置松手之后来通知适配器执行这个方法notifyItemMoved(int fromPosition, int toPosition)进行位置移动呀。那我们就需要把拖拽开始的位置和结束的位置记录下来,然后通知给适配器进行更新。我们就需要定义一个接口来传递起点和终点位置来通知适配器,进行更新。接下来我们来定义接口:代码如下:

public interface OnMoveItemLisenner{    //我们需要其实位置和终点位置。    public boolean onMoveItemLisenner(int fromStartposition,int toEndposition);}
 接下来我们需要让适配器实现我们的接口:等待回调时候替换位置。代码如下:
@Overridepublic boolean onMoveItemLisenner(int fromStartposition, int toEndposition) {   notifyItemMoved(fromStartposition,toEndposition);   return false;}
  最后我们需要在onMove()方法中去开启回调。首先我们需要在自定义的ItemTouchHelperCallBack里面  持有实现接口的适配器实例对象,才能进行回调实现。所以我们在activity里面来传递参数里面传递一个实  现了我们接口的适配器,让ItemTouchHelperCallBack持有它。代码如下:
itemTouchHelper=new ItemTouchHelper(new ItemTouchHelperCallBack(mAdapter));
最后我们在onMove里面进行开启回调,通知适配器进行移动更新。
    //拖拽@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {    return true;}我们在这个方法里面进行设置://拖拽@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {  //这个判断可以不写。如果你的布局是但布局。如果列表时多布局,那么只有相同类型的才可以移动。    if(viewHolder.getItemViewType()==target.getItemViewType()){        int startPosition = viewHolder.getAdapterPosition();        int endPosition = target.getAdapterPosition();        boolean moveflag=onMoveItemLisenner.onMoveItemLisenner(startPosition,endPosition);        if(moveflag){            return true;        }else {            return false;        }    }else{      return false;    }}
  到目前所有的事基本做完。但是我运行之后发现拖拽之后列表活动到低端,再看列表item又回到拖拽之前的位  置,我们这里忘记在通知替换位置之前没有替换两个位置的数据。我们在这里需要替换数据。  Collections.swap(list,fromStartposition,toEndposition);其实在javaAPI中提供很多方  法,没必要自己去替换。
@Overridepublic boolean onMoveItemLisenner(int fromStartposition, int toEndposition) {   Collections.swap(list,fromStartposition,toEndposition);   notifyItemMoved(fromStartposition,toEndposition);   return true;}

最终完成了RecyclerView的拖拽动画。如下图:
这里写图片描述
我下面贴出gitHub下载地址:
https://github.com/luhenchang/Lsn6_MaterialDesign_Recycler_ItemTouchHelper.git

原创粉丝点击