讲起本篇博客的历史起源,估计有一段“历史”了。
最早可以追溯到我试玩探探这个 APP 。第一次进入软件界面,就被这种通过卡片式滑动来选择“喜欢/不喜欢”的设计所吸引了。当时就非常想通过自己来实现这种仿探探式的效果,然而却没什么思路。不过毋庸置疑的是,这种效果的原理肯定和 ListView / RecyclerView 类似,涉及到 Item View 的回收和重用,否则早就因为大量的 Item View 而 OOM 了。
再到后来,看到许多大神也推出了同样仿探探效果的博客,从头到尾阅读下来,写得通俗易懂,基本上没什么问题。于是,实现仿探探效果的想法再次出现在脑海中。那么,还犹豫什么,趁热来一发吧!就这么愉快地决定了。
首先面临的问题就是关于实现 View 上的考虑。毫无疑问,
RecyclerView 是最佳选择!
RecyclerView 是最佳选择!
RecyclerView 是最佳选择!
重要的话讲三遍!!!
究其原因,第一,RecyclerView 是自带 Item View 回收和重用功能的,就不需要我们考虑这个问题了;第二,RecyclerView 的布局方式是通过设置 LayoutManager 来实现的,这样就充分地把布局和 RecyclerView “解耦”开来了。而 LayoutManager 是可以通过自定义的方式来实现的。这恰恰是我们想要的!!!再说一点,这也正是不选用 ListView 的原因之一。
下面,我们就开始动手了。带你见证奇迹的时刻。
CardLayoutManager
创建 CardLayoutManager
并继承自 RecyclerView.LayoutManager
。需要我们自己实现 generateDefaultLayoutParams()
方法:
1 | @Override |
一般情况下,像上面这样写即可。
下面这个方法就是我们的重点了。 onLayoutChildren(final RecyclerView.Recycler recycler, RecyclerView.State state)
方法就是用来实现 Item View 布局的:
1 | @Override |
总体来说,CardLayoutManager
主要就是为 Item View 布局,然后根据 position
做相对应的偏差。我们一起来看下完成的效果图:
可以看出,大致的效果已经有了。缺少的就是处理触摸滑动事件了。
OnSwipeListener
在看滑动事件的代码之前,我们先定义一个监听器。主要用于监听卡片滑动事件,代码就如下所示,注释也给出来了。应该都看得懂吧:
1 | public interface OnSwipeListener<T> { |
CardItemTouchHelperCallback
现在,我们可以回过头来看看卡片滑动了。对于 ItemTouchHelper 来处理 Item View 的触摸滑动事件相必都不陌生吧,如果对这方面不太了解的同学可以看一下我之前的博客:《RecyclerView实现拖拽排序和侧滑删除》。
我们暂且命名为 CardItemTouchHelperCallback 。对于 ItemTouchHelper.Callback 而言,需要在 getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
方法中配置 swipeFlags
和 dragFlags
。
具体的方法如下,对于 swipeFlags
只关心左右两个方向:
1 | @Override |
还有一点需要注意,前面说过,为了防止第二层和第三层卡片也能滑动,因此我们需要设置 isItemViewSwipeEnabled()
返回 false 。
1 | @Override |
接下来,就是去重写 onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
和 onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
方法。但是因为在上面我们对于 dragFlags
配置的是 0 ,所以在 onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
中直接返回 false 即可。
1 | @Override |
这样,我们就把目光投向 onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
方法:
1 | @Override |
写好后,我们先来看看滑动效果:
发现还是差了点什么,没错!是缺少了动画。在滑动的过程中我们可以重写 onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive)
方法来添加动画:
1 | @Override |
现在我们加上动画后,来看看效果:
发现还是有问题,第一层的卡片滑出去之后第二层的就莫名其妙地偏了。这正是因为 Item View 重用机制“捣鬼”。所以我们应该在 clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
方法中重置一下:
1 | @Override |
大功告成,我们试一下效果:
Perfect !
这正是我们梦寐以求的效果。我们终于实现了!!!
总结一下,在这整个代码流程中我们主要是运用了自定义 LayoutManager 以及 ItemTouchHelper.Callback 。总体来说还是比较简单的,相信你已经会啦。
Goodbye ~~
最后,放上 GitHub 地址:yuqirong/CardSwipeLayout
喜欢的可以来一波 star 哦。@^_^@