如何判断FragmentManager是否在执行动画及Fragment切换动画实现问题
嘿,针对你的两个Fragment相关问题,我整理了具体的解决方案:
问题1:如何观察FragmentManager当前是否有动画正在运行?
有几种实用的方式可以判断FragmentManager是否有动画在执行,根据你的需求选择:
- 直接使用API判断(推荐):如果你的项目使用AndroidX Fragment 1.3.0及以上版本,可以直接调用FragmentManager的
isRunningAnimations()方法,它会返回当前是否有Fragment相关的动画正在运行,用法非常简单:
// 以Activity中的supportFragmentManager为例 val isAnimating = supportFragmentManager.isRunningAnimations()
- 监听单个Fragment的动画生命周期:如果需要更精细地追踪某个特定Fragment的动画状态,可以在该Fragment中重写
onCreateAnimation()或onCreateAnimator()方法,通过动画监听器标记状态:
class CatFragment : Fragment() { private var isFragmentAnimating = false override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? { val animation = super.onCreateAnimation(transit, enter, nextAnim) animation?.apply { setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation?) { isFragmentAnimating = true } override fun onAnimationEnd(animation: Animation?) { isFragmentAnimating = false } override fun onAnimationRepeat(animation: Animation?) {} }) } return animation } // 对外提供判断方法 fun isAnimating(): Boolean = isFragmentAnimating }
之后你可以通过Fragment实例的isAnimating()方法判断它是否有动画在运行,如果需要全局判断所有Fragment的动画状态,遍历FragmentManager中的所有Fragment并检查即可。
- 监听事务提交辅助判断:如果你是自己发起的Fragment事务,可以通过
addOnTransactionCommitListener监听事务提交完成,但注意事务完成不代表动画结束,动画是在事务提交后才开始执行的,所以这个方法只能作为辅助,不能直接判断动画是否在运行。
问题2:实现CatFragment与DogFragment的淡入淡出切换,同时保留CatFragment内部状态动画
要在CatFragment之上添加DogFragment并实现crossfade动画,同时不影响CatFragment内部的状态切换动画,按以下步骤操作:
1. 准备动画资源(可选,也可以用代码实现)
在res/anim目录下创建两个淡入淡出的动画文件:
fade_in.xml(DogFragment进入动画):
<?xml version="1.0" encoding="utf-8"?> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromAlpha="0.0" android:toAlpha="1.0" />
fade_out.xml(CatFragment淡出动画):
<?xml version="1.0" encoding="utf-8"?> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromAlpha="1.0" android:toAlpha="0.0" />
2. 实现Fragment间的Crossfade动画
因为是添加DogFragment到CatFragment之上(而非替换),CatFragment不会被移除,所以需要同时给CatFragment的视图添加淡出动画,DogFragment的视图添加淡入动画:
// 在Activity或父Fragment中执行添加操作 fun addDogFragment() { // 获取当前显示的CatFragment val catFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as? CatFragment catFragment?.view?.let { catView -> // 让CatFragment的视图淡出 catView.animate() .alpha(0f) .setDuration(300) .start() } // 创建并添加DogFragment val dogFragment = DogFragment() supportFragmentManager.beginTransaction() .add(R.id.fragment_container, dogFragment) .addToBackStack(null) // 可选,允许用户返回CatFragment .commit() }
然后在DogFragment的onViewCreated方法中,给自身视图添加淡入动画:
class DogFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 初始设置视图透明,然后执行淡入 view.alpha = 0f view.animate() .alpha(1f) .setDuration(300) .start() } }
如果需要在返回时让CatFragment重新淡入,可以在DogFragment的onDestroyView中触发CatFragment的淡入动画:
override fun onDestroyView() { super.onDestroyView() val catFragment = parentFragmentManager.findFragmentById(R.id.fragment_container) as? CatFragment catFragment?.view?.animate() ?.alpha(1f) ?.setDuration(300) ?.start() }
3. 保留CatFragment内部状态切换动画
CatFragment内部的状态切换动画是视图级别的,和Fragment间的动画互不干扰,你可以继续使用原来的实现方式,比如:
class CatFragment : Fragment() { private lateinit var catImageView: ImageView private lateinit var loadingProgressBar: ProgressBar override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) catImageView = view.findViewById(R.id.cat_image) loadingProgressBar = view.findViewById(R.id.loading_bar) } // 切换到Loading状态 fun switchToLoadingState() { catImageView.animate() .alpha(0f) .setDuration(300) .withEndAction { catImageView.visibility = View.GONE loadingProgressBar.visibility = View.VISIBLE loadingProgressBar.animate() .alpha(1f) .setDuration(300) .start() } .start() } // 切换到Cat状态 fun switchToCatState() { loadingProgressBar.animate() .alpha(0f) .setDuration(300) .withEndAction { loadingProgressBar.visibility = View.GONE catImageView.visibility = View.VISIBLE catImageView.animate() .alpha(1f) .setDuration(300) .start() } .start() } }
这样就能保证两种动画都能正常运行,不会互相冲突。
内容的提问来源于stack exchange,提问作者ZakTaccardi
相关产品推荐
相关产品推荐

