使用removeView()从AppBarLayout移除TabLayout时出现异常动画问题
我之前在处理AppBarLayout和TabLayout的动态交互时,也碰到过一模一样的诡异动画问题,你的情况本质上是AppBarLayout的内部状态和View的添加/移除时机没协调好导致的,下面给你详细分析和解决办法:
问题根源
AppBarLayout作为CoordinatorLayout的核心子布局,内部维护着滚动、展开/折叠的状态逻辑,还绑定了一系列Behavior的动画回调。当你直接调用appbar.removeView(tabs)时,如果此时AppBarLayout正处于动画执行状态(比如用户刚滑动过RecyclerView,AppBar还在折叠/展开过渡),就会打断它的内部状态流程,触发CoordinatorLayout的状态恢复机制,导致TabLayout被“误添加”回去,最后才完成真正的移除动画。
而重新添加TabLayout时的代码,没有等待布局稳定就调用setExpanded,也会导致布局计算和动画逻辑冲突,出现异常。
解决方案1:正确移除TabLayout(带动画)
不要直接调用removeView,而是先给TabLayout做退出动画,等动画结束后再真正移除,同时通知AppBarLayout重新计算布局:
Kotlin代码:
// 给TabLayout添加退出动画 tabs.animate() .alpha(0f) .translationY(-tabs.height.toFloat()) .setDuration(300) // 和AppBar的动画时长保持一致 .setListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator?) {} override fun onAnimationEnd(animation: Animator?) { // 动画结束后再移除View appbar.removeView(tabs) // 强制AppBarLayout重新计算布局,同步状态 appbar.requestLayout() } override fun onAnimationCancel(animation: Animator?) {} override fun onAnimationRepeat(animation: Animator?) {} })
Java代码:
tabs.animate() .alpha(0f) .translationY(-tabs.getHeight()) .setDuration(300) .setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) {} @Override public void onAnimationEnd(Animator animation) { appbar.removeView(tabs); appbar.requestLayout(); } @Override public void onAnimationCancel(Animator animation) {} @Override public void onAnimationRepeat(Animator animation) {} });
解决方案2:修复重新添加TabLayout的异常
重新添加时,要确保TabLayout已经完全脱离原父容器,并且等待布局完成后再触发AppBar的展开动画:
Kotlin代码:
// 先处理TabLayout的移除(如果还在父容器中) (tabs.parent as? ViewGroup)?.let { parent -> if (parent == appbar) { // 先做隐藏动画再移除 tabs.animate().alpha(0f).setDuration(200).withEndAction { parent.removeView(tabs) // 移除后再添加到AppBar appbar.addView(tabs) tabs.alpha = 1f // 恢复可见性 // 等待TabLayout完成布局后,再触发展开动画 tabs.post { appbar.setExpanded(true, true) } } } else { // 不在AppBar里直接添加 appbar.addView(tabs) tabs.post { appbar.setExpanded(true, true) } } }
额外建议
如果你的项目还在使用旧版的android.support.design库,建议尽快升级到AndroidX的com.google.android.material:material库,新版修复了大量CoordinatorLayout和AppBarLayout的动画冲突bug,能从根源减少这类问题的出现。
内容的提问来源于stack exchange,提问作者BigDX

