如何解决RecyclerView中MotionLayout实现的列表项动画滚动时混乱的问题
问题根源及修复方案
核心问题
滚动动画混乱是三个原因共同导致的:
- 没有将MotionLayout的展开/收起状态绑定到数据源,仅存在View上,ViewHolder复用时会携带之前item的状态
- 调用带动画的
transitionToStart()重置状态时,滚动过程中动画未执行完成就被再次复用,出现视觉错乱 - MotionScene中自带的
<OnClick>触发器和数据源状态无关联,点击触发的状态不会同步到数据源
具体修复步骤
1. 给数据源加状态标记
在Story数据类中新增字段存储展开状态:
data class Story( // 原有字段保持不变 var isExpanded: Boolean = false )
2. 绑定数据时无动画重置状态
修改ViewHolder的set()方法,绑定数据时直接切到对应状态,不要走过渡动画:
fun set(story: Story) { this.story = story Glide .with(mainView.context) .load(story.image) .centerCrop() .into(storyImage) storyTitleTv.text = story.title storyAuthorTv.text = "" addTags(story.tags) // 新增:无动画直接切到对应状态 root.apply { if (story.isExpanded) { setProgress(1f) } else { setProgress(0f) } } }
3. 移除MotionScene自带点击触发器,自行控制状态切换
首先删除MotionScene中<Transition>标签下的<OnClick motion:targetId="@+id/story_image" />代码。
然后修改ViewHolder中storyImage的点击逻辑,同步更新数据源状态:
init { // 原有其他点击逻辑保持不变 storyImage.setOnClickListener { story.isExpanded = !story.isExpanded if (story.isExpanded) { root.transitionToEnd() } else { root.transitionToStart() } } }
4. 可选优化:复用时立即停止动画
在ViewHolder中新增回收回调方法,复用时直接终止未完成的动画,避免状态错乱:
fun onRecycled() { // 立即结束当前所有过渡动画 root.transitionToState(root.currentState, 0) }
在Adapter的onViewRecycled()方法中调用该方法即可。
额外注意
你当前的start ConstraintSet是空的,建议把布局初始状态的约束明确写到start标签里,不要依赖MotionLayout自动解析布局默认约束,避免部分系统版本出现解析异常。
内容的提问来源于stack exchange,提问作者MoonX App
相关产品推荐
相关产品推荐

