You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fragment触发onPause时onAnimationEnd未被调用的问题求解

解决AnimationListener的onAnimationEnd在Fragment切换时不触发的问题

核心原因

切换Fragment时,原Fragment的View会被从Window中移除(或进入不可见状态),系统会自动取消绑定在该View上的Animation,导致onAnimationEnd不会被调用。Handler或Coroutine仅负责线程切换,无法改变系统对View动画的生命周期管理逻辑。

具体解决方案

1. 关联Fragment视图生命周期,主动处理动画状态

在Fragment中利用viewLifecycleOwner的生命周期回调,在View暂停/销毁时手动控制动画状态,避免逻辑丢失:

private var animation: Animation? = null
private var isAnimationRunning = false

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    animation = AlphaAnimation(1f, 0f).apply {
        duration = 1000
        setAnimationListener(object : Animation.AnimationListener {
            override fun onAnimationEnd(animation: Animation) {
                isAnimationRunning = false
                Log.d("TAG", "onAnimationEnd")
                // 执行你的结束逻辑
            }
            override fun onAnimationStart(animation: Animation) {
                isAnimationRunning = true
            }
            override fun onAnimationRepeat(animation: Animation) {}
        })
    }
}

override fun onPause() {
    super.onPause()
    animation?.let {
        if (it.hasStarted() && !it.hasEnded()) {
            it.cancel()
            // 可选:直接触发结束逻辑,避免任务遗漏
            // onAnimationEnd(it)
        }
    }
}

override fun onResume() {
    super.onResume()
    if (isAnimationRunning) {
        view.startAnimation(animation)
    }
}

2. 改用ViewPropertyAnimator替代传统Animation

ViewPropertyAnimator的生命周期感知更贴合View状态,doOnEnd回调不受Fragment直接切换影响(只要View未被销毁):

view.animate()
    .alpha(0f)
    .setDuration(1000)
    .doOnEnd {
        Log.d("TAG", "Animation ended")
        // 执行你的结束逻辑
    }
    .start()

3. 将动画结束逻辑与视图解耦,迁移至ViewModel

如果动画结束后的操作不依赖当前Fragment的View,可以把逻辑放到ViewModel中,通过LiveData通知Fragment执行UI操作:

// ViewModel类
class MyViewModel : ViewModel() {
    private val _animationEnded = MutableLiveData<Boolean>()
    val animationEnded: LiveData<Boolean> = _animationEnded

    fun triggerAnimationEnd() {
        _animationEnded.postValue(true)
    }
}

// Fragment中
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val viewModel = ViewModelProvider(this)[MyViewModel::class.java]
    
    view.animate()
        .alpha(0f)
        .setDuration(1000)
        .doOnEnd {
            viewModel.triggerAnimationEnd()
        }
        .start()

    viewModel.animationEnded.observe(viewLifecycleOwner) {
        Log.d("TAG", "onAnimationEnd from ViewModel")
        // 执行动画结束后的UI逻辑
    }
}

4. 手动计算动画进度,确保逻辑执行

如果必须保证结束逻辑执行,可在启动动画时记录时间点,在Fragment生命周期变化时判断是否触发逻辑:

private var animationStartTime: Long = 0
private val animationDuration = 1000L

private fun startAnimation() {
    animationStartTime = System.currentTimeMillis()
    val animation = AlphaAnimation(1f, 0f).apply {
        duration = animationDuration.toInt()
        setAnimationListener(object : Animation.AnimationListener {
            override fun onAnimationEnd(animation: Animation) {
                handleAnimationEnd()
            }
            override fun onAnimationStart(animation: Animation) {}
            override fun onAnimationRepeat(animation: Animation) {}
        })
    }
    view.startAnimation(animation)
}

override fun onPause() {
    super.onPause()
    val elapsedTime = System.currentTimeMillis() - animationStartTime
    // 动画已执行足够时长,直接触发结束逻辑
    if (elapsedTime >= animationDuration) {
        handleAnimationEnd()
    }
}

private fun handleAnimationEnd() {
    Log.d("TAG", "onAnimationEnd")
    // 你的结束逻辑
}

内容的提问来源于stack exchange,提问作者GHH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:50:28