ItemTouchHelper.Callback 详解


ItemTouchHelper是在操作RecyclerView时,堆Item进行长按移动,左右滑动删除效果的一个辅助类,但是我们要考虑,为什么这个辅助类就可以实现移动跟左右删除Item的效果呢?我们的touch事件是怎么作用到RecyclerView的Item上呢?我们通过源码的解析都是可以知道这是为什么的。

下面开始:

创建一个ItemTouchHelper,需要传入一个继承自ItemTouchHelper.Callback
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback(adapter));
itemTouchHelper.attachToRecyclerView(recyclerView);

我们先介绍下这个ItemTouchHelper.Callback这个类以及里面的方法:

这个方法用于让RecyclerView拦截向上滑动,向下滑动,想左滑动
makeMovementFlags(dragFlags, swipeFlags);dragFlags是上下方向的滑动 swipeFlags是左右方向上的滑动
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    return makeMovementFlags(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.LEFT);
}

/**
 * drag状态下,在canDropOver()返回true时,会调用该方法让我们拖动换位置的逻辑(需要自己处理变换位置的逻辑)
 */
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    if(mListener != null){
        mListener.onMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
    }
    return true;
}
/**
 * 针对drag状态,当前target对应的item是否允许移动
 * 我们一般用drag来做一些换位置的操作,就是当前对应的target对应的Item可以移动
 */
@Override
public boolean canDropOver(RecyclerView recyclerView, RecyclerView.ViewHolder current, RecyclerView.ViewHolder target) {
    return true;
}

/**
 * 针对drag状态,当drag ItemView跟底下ItemView重叠时,可以给drag ItemView设置一个Margin值
 * 让重叠不容易发生,相当于增大了drag Item的区域
 */
@Override
public int getBoundingBoxMargin() {
    return 0;
}
/**
 * 针对drag状态,当滑动超过多少就可以出发onMove()方法(这里指onMove()方法的调用,并不是随手指移动的View)
 */
public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
    return .5f;
}
/**
 * 针对drag状态,在drag的过程中获取drag itemView底下对应的ViewHolder(一般不用我们处理直接super就好了)
 */
public RecyclerView.ViewHolder chooseDropTarget(RecyclerView.ViewHolder selected,
                                                List<RecyclerView.ViewHolder> dropTargets,
                                                int curX,
                                                int curY) {
    return super.chooseDropTarget(selected, dropTargets, curX, curY);
}
/**
 * 当onMove return true的时候调用(一般不用我们自己处理,直接super就好)
 */
public void onMoved(final RecyclerView recyclerView,
                    final RecyclerView.ViewHolder viewHolder,
                    int fromPos,
                    final RecyclerView.ViewHolder target,
                    int toPos,
                    int x,
                    int y) {
    super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
}
/**
 * 针对swipe和drag状态,当一个item view在swipe、drag状态结束的时候调用
 * drag状态:当手指释放的时候会调用
 * swipe状态:当item从RecyclerView中删除的时候调用,一般我们会在onSwiped()函数里面删除掉指定的item view
 */
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    super.clearView(recyclerView, viewHolder);
    viewHolder.itemView.setBackgroundColor(Color.TRANSPARENT);
    viewHolder.itemView.setAlpha(1);
    viewHolder.itemView.setScaleY(1);
    viewHolder.itemView.setScaleX(1);
}
/**
 * 针对swipe和drag状态,整个过程中一直会调用这个函数,随手指移动的view就是在super里面做到的(和ItemDecoration里面的onDraw()函数对应)
 */
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
        float alpha = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
        viewHolder.itemView.setAlpha(alpha);
        viewHolder.itemView.setScaleX(alpha);
        viewHolder.itemView.setScaleY(alpha);
    }
    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
/**
 * 针对swipe和drag状态,整个过程中一直会调用这个函数(和ItemDecoration里面的onDrawOver()函数对应)
 * 这个函数提供给我们可以在RecyclerView的上面再绘制一层东西,比如绘制一层蒙层啥的
 */
public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
/**
 * 针对swipe和drag状态,当手指离开之后,view回到指定位置动画的持续时间(swipe可能是回到原位,也有可能是swipe掉)
 */
public long getAnimationDuration(RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
    return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
}
/**
 * 针对drag状态,当itemView滑动到RecyclerView边界的时候(比如下面边界的时候),RecyclerView会scroll,
 * 同时会调用该函数去获取scroller距离(不用我们处理 直接super)
 */
public int interpolateOutOfBoundsScroll(RecyclerView recyclerView,
                                        int viewSize,
                                        int viewSizeOutOfBounds,
                                        int totalSize,
                                        long msSinceStartScroll) {
    return super.interpolateOutOfBoundsScroll(recyclerView, viewSize, viewSizeOutOfBounds, totalSize, msSinceStartScroll);
}
/**
 * 针对swipe和drag状态,当swipe或者drag对应的ViewHolder改变的时候调用
 * 我们可以通过重写这个函数获取到swipe、drag开始和结束时机,viewHolder 不为空的时候是开始,空的时候是结束
 */
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
    if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE || actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
        viewHolder.itemView.setBackgroundColor(Color.parseColor("#3F51B5"));
    }
    super.onSelectedChanged(viewHolder, actionState);
}
/**
 * 针对swipe状态,是否允许swipe(滑动)操作
 */
public boolean isItemViewSwipeEnabled() {
    return true;
}
/**
 * 针对swipe状态,swipe滑动的位置超过了百分之多少就消失
 */
public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
    return .5f;
}
/**
 * 针对swipe状态,swipe的逃逸速度,换句话说就算没达到getSwipeThreshold设置的距离,达到了这个逃逸速度item也会被swipe消失掉
 */
public float getSwipeEscapeVelocity(float defaultValue) {
    return defaultValue;
}
/**
 * 针对swipe状态,swipe滑动的阻尼系数,设置最大滑动速度
 */
public float getSwipeVelocityThreshold(float defaultValue) {
    return defaultValue;
}
/**
 * 针对swipe状态,swipe 到达滑动消失的距离回调函数,一般在这个函数里面处理删除item的逻辑
 * 确切的来讲是swipe item滑出屏幕动画结束的时候调用
 */
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    if(mListener != null){
        mListener.onRemove(viewHolder.getAdapterPosition());
    }
}
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
    private ItemTouchListener mListener;
    public ItemTouchHelperCallback(ItemTouchListener listener){
        mListener = listener;
    }
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        return makeMovementFlags(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.LEFT);
    }
    @Override
    /**
     * 针对swipe状态,swipe 到达滑动消失的距离回调函数,一般在这个函数里面处理删除item的逻辑
     * 确切的来讲是swipe item滑出屏幕动画结束的时候调用
     */
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        if(mListener != null){
            mListener.onRemove(viewHolder.getAdapterPosition());
        }
    }
    /**
     * drag状态下,在canDropOver()返回true时,会调用该方法让我们拖动换位置的逻辑(需要自己处理变换位置的逻辑)
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        if(mListener != null){
            mListener.onMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
        }
        return true;
    }
    @Override
    /**
     * 针对swipe和drag状态,整个过程中一直会调用这个函数,随手指移动的view就是在super里面做到的(和ItemDecoration里面的onDraw()函数对应)
     */
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
            float alpha = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
            viewHolder.itemView.setAlpha(alpha);
            viewHolder.itemView.setScaleX(alpha);
            viewHolder.itemView.setScaleY(alpha);
        }
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }

    @Override
    /**
     * 针对swipe和drag状态,整个过程中一直会调用这个函数(和ItemDecoration里面的onDrawOver()函数对应)
     * 这个函数提供给我们可以在RecyclerView的上面再绘制一层东西,比如绘制一层蒙层啥的
     */
    public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }

    @Override
    /**
     * 针对swipe和drag状态,当一个item view在swipe、drag状态结束的时候调用
     * drag状态:当手指释放的时候会调用
     * swipe状态:当item从RecyclerView中删除的时候调用,一般我们会在onSwiped()函数里面删除掉指定的item view
     */
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setBackgroundColor(Color.TRANSPARENT);
        viewHolder.itemView.setAlpha(1);
        viewHolder.itemView.setScaleY(1);
        viewHolder.itemView.setScaleX(1);
    }
}
interface ItemHelperListener {
    /**
     * 删除时的回调
     */
    fun onRemove(position:Int)

    /**
     * 交换时的回调
     */
    fun onSwap(formPosition:Int, toPosition:Int)
}
public class MyAdapter2 extends RecyclerView.Adapter implements IListener,ItemTouchListener{

@Override
public void onMove(int from, int to) {
    Collections.swap(mData,from,to);
    notifyItemMoved(from,to);
}

@Override
public void onRemove(int position) {
    mData.remove(position);
    notifyItemRemoved(position);
}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值