Android:无需第三方库实现RecyclerView类Tinder滑动卡片及回调
Android RecyclerView实现无第三方库的Tinder式滑动卡片(带动画)
核心思路
利用RecyclerView自带的ItemTouchHelper处理滑动手势,自定义ItemTouchHelper.Callback实现Tinder风格的滑动动画(倾斜+位移),同时通过自定义接口回调传递卡片出现/消失的位置、滑动方向,滑动完成后自动移除数据并刷新列表。
具体实现步骤
1. 定义滑动回调接口
用于传递卡片状态信息:
interface CardSwipeCallback { // 返回即将显示的卡片位置(滑动后露出的下一张) fun onCardAppear(position: Int) // 返回被滑走的卡片位置 fun onCardDisappear(position: Int) // 返回当前滑动方向:ItemTouchHelper.LEFT / ItemTouchHelper.RIGHT fun onCardSwipeDirection(direction: Int) }
2. 自定义ItemTouchHelper.Callback
处理滑动逻辑、动画及回调触发:
class TinderSwipeCallback( private val adapter: RecyclerView.Adapter<*>, private val callback: CardSwipeCallback ) : ItemTouchHelper.Callback() { override fun getMovementFlags( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder ): Int { // 仅允许左右滑动 val swipeFlags = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT return makeMovementFlags(0, swipeFlags) } override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean = false // 不需要拖拽移动 override fun onChildDraw( c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean ) { // 添加滑动倾斜动画,模拟Tinder卡片的倾斜效果 val itemView = viewHolder.itemView val rotation = dX * 0.1f // 倾斜角度随滑动距离线性变化 itemView.rotation = rotation // 保留系统默认的滑动位移逻辑 super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { val position = viewHolder.adapterPosition // 触发消失卡片的回调 callback.onCardDisappear(position) // 触发滑动方向回调 callback.onCardSwipeDirection(direction) // 移除数据并刷新列表 (adapter as CardAdapter).removeItem(position) // 若还有剩余卡片,触发下一张卡片的出现回调 if (adapter.itemCount > 0) { callback.onCardAppear(0) // 堆叠布局下,下一张卡片始终在position 0 } } override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { super.clearView(recyclerView, viewHolder) // 滑动结束后重置卡片旋转角度 viewHolder.itemView.rotation = 0f } }
3. 实现RecyclerView Adapter
处理数据绑定与移除逻辑:
class CardAdapter(private val dataList: MutableList<String>) : RecyclerView.Adapter<CardAdapter.CardViewHolder>() { inner class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val cardContent: TextView = itemView.findViewById(R.id.tv_card_content) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_card, parent, false) return CardViewHolder(view) } override fun onBindViewHolder(holder: CardViewHolder, position: Int) { holder.cardContent.text = dataList[position] } override fun getItemCount(): Int = dataList.size fun removeItem(position: Int) { dataList.removeAt(position) notifyItemRemoved(position) } }
4. 界面配置与回调实现
在Activity/Fragment中完成RecyclerView初始化、绑定ItemTouchHelper,并实现回调接口:
class MainActivity : AppCompatActivity(), CardSwipeCallback { private lateinit var recyclerView: RecyclerView private lateinit var adapter: CardAdapter private val dataList = mutableListOf("卡片1", "卡片2", "卡片3", "卡片4", "卡片5") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) recyclerView = findViewById(R.id.recycler_view) // 自定义LayoutManager,禁止垂直滑动,模拟堆叠效果 recyclerView.layoutManager = object : LinearLayoutManager(this) { override fun canScrollVertically(): Boolean = false } adapter = CardAdapter(dataList) recyclerView.adapter = adapter // 绑定ItemTouchHelper val swipeCallback = TinderSwipeCallback(adapter, this) ItemTouchHelper(swipeCallback).attachToRecyclerView(recyclerView) // 初始触发第一张卡片的出现回调 if (dataList.isNotEmpty()) { onCardAppear(0) } } override fun onCardAppear(position: Int) { // 这里可添加卡片出现的业务逻辑,比如日志、状态更新 println("出现的卡片位置:$position") } override fun onCardDisappear(position: Int) { // 这里可添加卡片消失的业务逻辑 println("消失的卡片位置:$position") } override fun onCardSwipeDirection(direction: Int) { val directionStr = if (direction == ItemTouchHelper.LEFT) "左滑" else "右滑" println("当前卡片滑动方向:$directionStr") } }
5. 布局优化(堆叠效果)
在item_card.xml中给CardView设置负top margin,让下一张卡片露出顶部边缘,模拟堆叠:
<?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:layout_marginTop="-20dp" <!-- 负margin实现堆叠 --> android:layout_marginBottom="16dp" android:elevation="8dp"> <TextView android:id="@+id/tv_card_content" android:layout_width="match_parent" android:layout_height="300dp" android:gravity="center" android:textSize="24sp"/> </androidx.cardview.widget.CardView>
注意事项
- 若需要更细腻的动画,可在
onChildDraw中添加透明度变化(itemView.alpha = 1 - abs(dX) / recyclerView.width) - 可通过修改
rotation的系数调整卡片倾斜程度,适配不同设计需求 - 若卡片数量较多,建议优化RecyclerView的回收机制,避免内存泄漏
内容的提问来源于stack exchange,提问作者Hassan Raza
相关产品推荐
相关产品推荐

