神奇的ItemTouchHelper

XSize的主页

device-2018-03-30-193500.gif

本文知识点:

  • 常用API的说明
  • ItemTouchHelper的使用案例
  • 常见的使用案例

1.常用的API说明

  • getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) 主要的作用是用来返回可以滑动的方向,主要是处理滑动方向的!分为上下滑动和左右滑动使用makeMovementFlags(int dragFlags, int swipeFlags)进行相应的返回(具体怎么写,下面说)

    • 参数1:recyclerView对象
    • 参数2:本类中的ViewHolder对象
  • onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)当条目发生移动的时候回调这个方法,一般是通过Adapter的notifyItemMoved(int fromPosition, int toPosition)方法进行条目的互换(这里别忘了把List的相应条目互换,下面说怎么做)这里有个返回值,一定要确保返回true否则不会生效的。。。

    • 参数1:recyclerView对象
    • 参数2:原始的ViewHolder对象
    • 参数3:目标的ViewHolder对象
  • onSwiped(RecyclerView.ViewHolder viewHolder, int direction) 当条目达到删除条件的时候会调用,怎么理解呢?也就是滑动条目到达一半的时候会回调这个方法(一般是用作滑动删除的时候使用这个方法,使用notifyItemRemoved(int position)将条目进行删除,别忘了把数据源中的数据删除);

    • 参数1:相应的ViewHolder
    • 参数2:这个是获取的方向
  • isLongPressDragEnabled()是否长按才能操作,这里你要是返回ture代表必须通过长按才能操作,默认也是true,一般操作都是这样的。。。

  • boolean boolean isItemViewSwipeEnabled() 是否可以进行左右删除操作,默认返回true,也只有这个方法返回true的时候才会执行onSwiped(RecyclerView.ViewHolder viewHolder, int direction)方法

  • onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)从静止状态变为其他状态的时候回调该方法

    • 参数1:ViewHolder对象
    • 参数2:表示当前的状态
  • clearView(RecyclerView recyclerView, ViewHolder viewHolder)当用户操作完毕某个item并且其动画也结束后会调用该方法,一般我们在该方法内恢复ItemView的初始状态,防止由于复用而产生的显示错乱问题。

  • onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)可以在这个方法内实现我们自定义的交互规则或者自定义的动画效果。

上面写了这么多的API相信大家已经烦了,但是我觉得去过这些API你不知道的话,真的没有办法好好理解下面的内容,所以我习惯把用到的API都先写出来,最起码混个脸熟。。。

下面进入到正题:实现RecyclerView的Item的处理,也就是最上面那种样式;

首先觉得CSDN_LQR在解耦和上做的很好,将相应的接口进行了拆分,自己也学习了一下这种思想,就是将相应的公共的内容通过接口进行连接;

1.相应的接口的实现

这里考虑到一个问题,首先在处理的时候都会处理相应的内容,有删除条目和条目互换的问题;所以这里通过接口的形式将关联放到相应的数据源处还是比较好的,这种思想可以借鉴一下。

public interface RecyclerItemHelper {
    //数据交换
    void onItemMove(int fromPosition, int toPosition);

    //数据删除
    void onItemDelete(int position);
}

2.实现相应的CallBack

public class RecyclerItemCallBack extends ItemTouchHelper.Callback {

    private static final String TAG = RecyclerItemHelper.class.getSimpleName();
    private RecyclerItemHelper mHelper;

    public RecyclerItemCallBack(RecyclerItemHelper helper) {
        mHelper = helper;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        Log.e(TAG, "getMovementFlags: ");
        //可以上下滑动
        int topAndBottom = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int leftAndRight = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        return makeMovementFlags(topAndBottom, leftAndRight);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        Log.e(TAG, "onMove: ");
        //这里是通过接口进行回调的
        mHelper.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        Log.e(TAG, "onSwiped: " + direction);
        mHelper.onItemDelete(viewHolder.getAdapterPosition());
    }
}

这里通过构造方法传递接口的形式(也就是上面的接口),将构造方法中传递进来,其实这里因为有两个是必须有的方法,如果是那种可以选择性实现的话,我会选择通过set的方法去添加接口。解释一下上面的代码,通过getMovementFlags()设置操作方向,当移动的时候
调用相应的回调方法,这里应该返回true确定回调触发了。如果你是左右滑动的时候,在滑动一半的时候会调用onSwiped()在这里确定了相应的删除操作。整体的逻辑就是这样,就是三个API的整合。

3.Apdpter的处理

class MainAdapter extends RecyclerView.Adapter implements RecyclerItemHelper {

    private List mList;

    public MainAdapter(RecyclerView rvContent) {
        //先实例化Callback
        ItemTouchHelper.Callback callback = new RecyclerItemCallBack(this);
        //用Callback构造ItemtouchHelper
        ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
        //调用ItemTouchHelper的attachToRecyclerView方法建立联系
        touchHelper.attachToRecyclerView(rvContent);
    }

    public void setData(List list) {
        if (null == list || list.size() == 0) return;
        mList = list;
        notifyDataSetChanged();
    }

    @Override
    public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view, parent, false);
        return new Holder(itemView);
    }

    @Override
    public void onBindViewHolder(Holder holder, int position) {
        holder.mText.setText(mList.get(position));
    }

    @Override
    public int getItemCount() {
        return null != mList ? mList.size() : 0;
    }

    @Override
    public void onItemMove(int fromPosition, int toPosition) {
        Collections.swap(mList, fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onItemDelete(int position) {
        Log.e("done", "onItemDelete: " + position);
        mList.remove(position);
        notifyItemRemoved(position);
    }

    public class Holder extends RecyclerView.ViewHolder {

        TextView mText;

        public Holder(View itemView) {
            super(itemView);
            mText = itemView.findViewById(R.id.tv_text);
        }
    }
}

这是Adapter的全部代码,和之前的写法没有什么区别,就是在构造方法中初始化并关联一个ItemTouchHelper就是那里面那三行代码,然后重写了两个函数,这里注意一个API就是Collections.swap(mList, fromPosition, toPosition);这个API是将list里面两个对象互换位置的API其他的就没有什么变化了。


基本上就这些代码,可以实现最上面的效果了。后续等有时间,研究一下侧拉删除的功能,如果你着急,可以看一下CSDN_LQR的文章讲到了这个功能!

特别感谢:
RecyclerView之使用ItemTouchHelper实现交互动画
CSDN_LQR关于ItemTouchHelper的讲解

你可能感兴趣的:(神奇的ItemTouchHelper)