AndroidUI初探④RecyclerView之ItemTouchHelper

0x000 前言

现在几乎养成了一种固定的写作模式 , 在开始正文之前 ,总想唠嗑几句 , 或技术简介亦或是近来的所思所想 , 都希望有个记录 , 与人分享交流 。这是一个开放的时代 , 我们很幸运的生活在这个时代 , 这么一个开放的时代 , 互联网将世界各地的知识信息传输到我们面前 , 几乎零距离 。然而 , 信息爆炸也成其了我们的不幸 , 每天被各种信息淹没 , 我们如一叶扁舟 , 在信息的大海里 , 如履薄冰 。

0x001 ItemTouchHelper

在 AndroidUI初探③RecyclerView之ItemDecoration中 , 介绍了RecyclerView Item之间怎样处理Style , ItemDecoration给了我们更多的想象 , 我们可以通过getItemOffsets来设置偏移量 , onDraw来绘制各种图形 , 可以通过Drawable来打造漂亮的ItemDecoration 。

如果说ItemDecoration是装饰Item的 , 那么ItemTouchHelper就是Item与用户交互的利器 。那么ItemTouchHelper是个什么样的类呢?他会为我们做些什么样的事情 。

ItemTouchHelper简介

源码中的解释是这样的 :

This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
大致说的是:这是一个RecyclerView的工具,提供了drag & swipe 的功能,也就是说 , 这个类可以帮助我们处理RecyclerView中Item的Drag和Swipe

It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.
大致说的是:他需要RecyclerView 还有ItemTouchHelper.CallBack配合使用,可以配置交互类型 , 并可以接收用户操作的事件 。也就是说 , 将ItemTouchHelper与RecyclerView关联之后 , CallBack可以接收到用户操作RecyclerView的事件 , 这样我们就可以做一些交互处理 。

英语渣渣 , 英语好的请忽略翻译

0x002 ItemTouchHelper的使用

一 , 创建ItemHelper对象

// 创建ItemTouchHelper的时候 , 就会要求我们传入CallBack , 用作RecyclerView事件的回调 , 并做出处理 。
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callBack);
// 关联RecylerView
itemTouchHelper.attachToRecyclerView(rvSimpleList);

二 , 实现CallBack

class ItemTouchHelperCallback extends ItemTouchHelper.Callback {

    /**
     * 需要处理的方向 , 如上下移动 , 左右滑动等
     * @param recyclerView
     * @param viewHolder
     * @return
     */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        return 0;
    }

    /**
     * 移动时会回调
     * @param recyclerView
     * @param viewHolder
     * @param target
     * @return
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    /**
     * 滑动时会回调
     * @param viewHolder
     * @param direction
     */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {

    }
}

只需两步 , 我们就可以将RecyclerView的事件接收掉 。那么他是怎么接收的呢 ? 我们深入源码看一看 。

0x003 ItemTouchHelper源码简析

在分析源码的时候 , 通常源码都会比较多 , 所以我们要找准主旨 , 我们是要分析ItemHelper是怎样将RecyclerView的事件接收起来的,那么我们主要看RecyclerView的事件处理,在ItemTouchHelper中是怎样体现的。

首先 , 从ItemTouchHelper关联RecyclerView方法看起 , attachToRecyclerView(@Nullable RecyclerView recyclerView) 这样方法就是我们ItemTouchHelper关联RecyclerView的开始 。

public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
        if (mRecyclerView == recyclerView) {
            return; // nothing to do
        }
        if (mRecyclerView != null) {
            destroyCallbacks();
        }
        mRecyclerView = recyclerView;
        if (mRecyclerView != null) {
            final Resources resources = recyclerView.getResources();
            mSwipeEscapeVelocity = resources
                    .getDimension(R.dimen.item_touch_helper_swipe_escape_velocity);
            mMaxSwipeVelocity = resources
                    .getDimension(R.dimen.item_touch_helper_swipe_escape_max_velocity);
            setupCallbacks();
        }
    }

得到了RecyclerView对象 , 接着就是将RecyclerView的TouchListener给抢过来 。进入setupCallbacks()我们可以看到 , 在ItemTouchHelper中设置的了RecyclerView的addOnItemTouchListener并且@OverrideonInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event) and onTouchEvent(RecyclerView recyclerView, MotionEvent event) and onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) .

onInterceptTouchEventonTouchEvent主要是将RecyclerView的TouchListener事件传递给ItemTouchHelper.Callback并做了相应的处理, 这样我们就可以在ItemTouchHelper的CallBack只关心我们想要处理的 。

事件传递代码块

if (mSelected == null) {
    final RecoverAnimation animation = findAnimation(event);
    if (animation != null) {
        mInitialTouchX -= animation.mX;
        mInitialTouchY -= animation.mY;
        endRecoverAnimation(animation.mViewHolder, true);
        if (mPendingCleanup.remove(animation.mViewHolder.itemView)) {
            // 事件传递
            mCallback.clearView(mRecyclerView, animation.mViewHolder);
        }
        // 主要交互处理
        select(animation.mViewHolder, animation.mActionState);
        updateDxDy(event, mSelectedFlags, 0);
    }
}

0x004 ItemTouchHelper简单示例

public class DragItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private final ViewHolderDragSwipeItemListener dragSwipeItemListener;

    public DragItemTouchHelperCallback(ViewHolderDragSwipeItemListener dragSwipeItemListener) {
        this.dragSwipeItemListener = dragSwipeItemListener;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

        /*拖拽方向*/
        int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;

        /*滑动方向*/
        int swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

        int flags = makeMovementFlags(dragFlag, swipeFlag);

        return flags;
    }

    /**
     * 是否开启长按拖拽 ,必须开启
     * @return
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }


    /**
     * 上下移动交换Item
     * @param recyclerView
     * @param viewHolder
     * @param target
     * @return
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        if (dragSwipeItemListener != null) {
            dragSwipeItemListener.onDragMoveSwap(viewHolder.getAdapterPosition(),target.getAdapterPosition());
        }
        return true;
    }

    /**
     * 左右滑动删除
     * @param viewHolder
     * @param direction
     */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
         if (dragSwipeItemListener != null) {
             dragSwipeItemListener.onSwipeDelete(viewHolder.getAdapterPosition());
         }
    }

    /**
     * 选中Item状态
     * @param viewHolder
     * @param actionState Item状态
     */
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
            return;
        }

        viewHolder.itemView.setBackgroundColor(Color.GRAY);

        super.onSelectedChanged(viewHolder, actionState);
    }

    /**
     * ItemView复位回调
     * @param recyclerView
     * @param viewHolder
     */
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setBackgroundColor(Color.WHITE);
        // Item会复用 , 所有操作ItemView的状态之后一定要复原
        viewHolder.itemView.setAlpha(1);
        viewHolder.itemView.setScaleX(1);
        viewHolder.itemView.setScaleY(1);
    }

    /**
     * 操作Item的时候会不断调用绘制Item , 我们可以在这里做很多事情。
     * @param c
     * @param recyclerView
     * @param viewHolder
     * @param dX
     * @param dY
     * @param actionState
     * @param isCurrentlyActive
     */
    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            float value = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
            viewHolder.itemView.setAlpha(value);
            viewHolder.itemView.setScaleX(value);
            viewHolder.itemView.setScaleY(value);
        }
    }
}

0x005 效果图

recyclerview_itemtouch_helper

0x006 The end

高手 , 都是通过不断的练习 。虽然有些事物看起简单 , 但深入其中 ,自会发现 , 每一件事都不是独立而存在 , 都是一环扣着一环 , 不要被表象迷惑 , 要敢于深究其理 。

源码 : AdvancedUI

你可能感兴趣的:(AndroidUI初探④RecyclerView之ItemTouchHelper)