如何实现RecyclerView Item触摸放大、释放缩小效果?
实现垂直RecyclerView Item触摸缩放效果(类似Facebook反应动效)
嘿,这个需求我之前也帮朋友搞过,类似Facebook那种轻触Item放大、松手就还原的动效其实没那么复杂,咱们一步步拆解来实现~
先聊核心逻辑
本质就是靠触摸事件监听+属性动画组合实现:
- 用户按下Item时,触发一个小幅度的放大动画(比如1.05倍,你可以自己调)
- 手指抬起或者触摸离开Item时,触发还原动画回到原尺寸
- 还要注意别和RecyclerView本身的滑动冲突,得让两者都正常工作
具体实现步骤
1. 写个全局的触摸监听类
我习惯写一个ItemScaleTouchListener实现RecyclerView.OnItemTouchListener,这样不用在Adapter里重复写代码,全局生效:
class ItemScaleTouchListener(private val recyclerView: RecyclerView) : RecyclerView.OnItemTouchListener { private var currentTouchedView: View? = null // 缩放参数,按需调整 private val SCALE_UP = 1.05f private val SCALE_NORMAL = 1.0f override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { when (e.action) { MotionEvent.ACTION_DOWN -> { // 找到当前触摸的那个Item View currentTouchedView = rv.findChildViewUnder(e.x, e.y) currentTouchedView?.let { scaleView(it, SCALE_UP) } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { currentTouchedView?.let { scaleView(it, SCALE_NORMAL) currentTouchedView = null } } } // 返回false,让RecyclerView正常处理滑动事件 return false } override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {} override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {} private fun scaleView(view: View, targetScale: Float) { // 先取消之前的动画,避免快速触摸导致动画混乱 view.animate().cancel() // 用属性动画做平滑缩放 ObjectAnimator.ofPropertyValuesHolder( view, PropertyValuesHolder.ofFloat(View.SCALE_X, targetScale), PropertyValuesHolder.ofFloat(View.SCALE_Y, targetScale) ).apply { duration = 150 // 动画时长,Facebook的动效大概是这个速度 interpolator = DecelerateInterpolator() // 减速插值器,放大时更自然 start() } } }
2. 给RecyclerView挂上这个监听
在你的Activity或者Fragment里,给RecyclerView添加这个监听就行:
recyclerView.addOnItemTouchListener(ItemScaleTouchListener(recyclerView))
3. 一些细节优化
- 如果你的Item里有按钮、CheckBox这类可点击的子View,得确保它们的触摸事件不受影响。可以在
onInterceptTouchEvent里判断触摸的View是不是可点击的,如果是就跳过缩放逻辑;或者调整子View的触摸优先级。 - 想让动效更像Facebook的话,可以把插值器换成
OvershootInterpolator(),放大时会有一点点回弹的感觉,更灵动。 - 要是你需要给不同Item设置不同的缩放比例,那不如直接在Adapter的
onBindViewHolder里给每个Item加触摸监听,比如:
override fun onBindViewHolder(holder: YourViewHolder, position: Int) { // 其他绑定逻辑... holder.itemView.setOnTouchListener { v, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { v.animate() .scaleX(1.05f) .scaleY(1.05f) .setDuration(150) .setInterpolator(DecelerateInterpolator()) .start() } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { v.animate() .scaleX(1.0f) .scaleY(1.0f) .setDuration(150) .setInterpolator(DecelerateInterpolator()) .start() } } // 这里返回false,让Item的点击事件能正常触发 false } }
这种方式更灵活,适合个性化需求多的场景。
内容的提问来源于stack exchange,提问作者Vitor Ferreira
相关产品推荐
相关产品推荐

