如何带动画实现RecyclerView展开时文本水平居中对齐
ConstraintLayout 内 setGravity 不生效的原因与修复方案
- 核心原因:
gravity属性仅控制文字在TextView控件内部的对齐,不会改变TextView本身在父布局中的位置。如果你给TextView设置的约束是单侧绑定父布局start/left边,哪怕TextView宽度是wrap_content,控件本身始终靠左摆放,文字在控件内居中也不会出现整体水平居中的视觉效果。 - 方案1:动态修改约束适配居中状态
展开状态下给TextView加上双向水平约束,让控件本身在ConstraintLayout内水平居中,再设置文字gravity即可:
val tvParams = targetText.layoutParams as ConstraintLayout.LayoutParams // 展开时设置双向约束 tvParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID tvParams.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID targetText.layoutParams = tvParams targetText.gravity = Gravity.CENTER_HORIZONTAL // 收起时恢复原单侧约束即可 // tvParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID // tvParams.endToEnd = ConstraintLayout.LayoutParams.UNSET // targetText.layoutParams = tvParams // targetText.gravity = Gravity.START
- 方案2:临时修改控件宽度适配
如果不想改约束,展开状态下直接把TextView宽度设为match_parent,此时调用setGravity(Gravity.CENTER_HORIZONTAL)会直接生效,收起时改回wrap_content和原gravity即可。
给布局变化添加过渡动画
- 不需要引入第三方库,直接用AndroidX原生的
TransitionManager就能自动捕获布局属性变化,生成丝滑的过渡动画,同时覆盖展开/收起的高度变化、文本位置移动、显隐切换所有效果。 - 实现代码非常简单,在修改布局属性(改约束、改gravity、改宽高、改子View可见性)之前,先给item根布局注册延迟过渡即可:
// 点击触发展开/收起的逻辑内 val itemRoot = itemView.findViewById<ConstraintLayout>(R.id.item_root_layout) // 初始化过渡效果 val transition = TransitionSet() .addTransition(ChangeBounds()) // 捕获位置、尺寸变化做动画 .addTransition(Fade()) // 捕获可见性变化做淡入淡出 .setDuration(350) // 自定义动画时长 .setInterpolator(AccelerateDecelerateInterpolator()) // 自定义插值器,让动画更自然 // 绑定过渡到根布局 TransitionManager.beginDelayedTransition(itemRoot, transition) // 过渡绑定完成后,再执行所有布局修改逻辑 if (currentItem.isExpanded) { // 执行展开的布局修改:改约束、设居中gravity、显示展开内容、修改item高度 } else { // 执行收起的布局修改:恢复原约束、设左对齐gravity、隐藏展开内容、修改item高度 }
- 适配RecyclerView复用的注意点:在
onBindViewHolder方法中,必须根据当前item的展开状态,直接给控件设置最终的约束、gravity、可见性属性,不要依赖动画执行后的状态,避免快速滑动列表时出现布局错乱。 - 想要更有辨识度的动画效果,可以自定义Transition实现,比如给文本移动加个轻微的回弹插值器
BounceInterpolator,或者给展开的内容加个位移动画,注意动画时长不要超过400ms,避免拖慢列表操作手感。
内容的提问来源于stack exchange,提问作者chrisChris
相关产品推荐
相关产品推荐

