在通过导航组件添加到动作的动画完成之前,防止点击视图

Prevent views from being clicked until animation added to action via navigation component completes

给定 2 个片段 ABA 移动到 B(所以 A -> B),通过带有输入动画的导航组件动作添加。如何防止 Fragment B 中的视图在进入动画 运行 时可点击?我发现了这个问题 How to add listener to android Navigation Architecture Component action animation 但不幸的是没有答案。

我在文档中发现,我可以通过挂接到 NavActionNavOptions 对象获取该动画的资源 ID,但不能通过 Animation 对象本身获取该动画的资源 ID。

您可以首先在 xml android:enabled="false" 中禁用您的视图,然后在片段的 onViewCreated 中您可以使用协程设置 delay 和动画持续时间:

override fun onViewCreated(view: View, savedState: Bundle?) {
    super.onViewCreated(view, savedState)

    // Initialize views here. 


    lifecycleScope.launch {
        delay(resources.getInteger(R.integer.anim_duration).toLong())
        // Enable views here
        myView.isEnabled = true
    }
}

虽然我最初使用协程解决了这个问题,但我遇到了同样的问题 再一次 :] 所以我做了一些调查,偶然发现了这个主题 Disable clicks when fragment adding animation playing,它帮助我找到了正确的解决方案。

显然那些通过导航图添加的动作动画是 由 FragmentTransaction.setCustomAnimation(enter, exit, popEnter, popExit) 设置 这些可以通过覆盖 onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int) 来访问。其中 nextAnim 实际上代表了我们添加的动作动画。对于片段 A,它将是 exitpopEnter,对于片段 B,它将是 enterpopExit

视图被点击的问题发生在片段进入(enterpopEnter)时,所以可以使用if语句检查enter和if true 基于 nextAnim 创建 Animation,然后可以为其设置侦听器。如果是主页(起始)片段,则应排除 nextAnim = 0 的情况,因为它也在进入动画。

override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
        if (nextAnim == 0 || !enter) return super.onCreateAnimation(transit, enter, nextAnim)
        else {
            return AnimationUtils.loadAnimation(requireContext(), nextAnim).apply {
                setAnimationListener(object : Animation.AnimationListener {
                    override fun onAnimationStart(animation: Animation?) {
                        disableClicking()
                    }

                    override fun onAnimationEnd(animation: Animation?) {
                        enableClicking()
                    }

                    override fun onAnimationRepeat(animation: Animation?) {
                    }
                })
            }
        }
    }

编辑:对于non-home片段,为了避免在动画开始时禁用点击,我们可以从xml布局中不可点击的视图开始,并且仅在动画结束时启用点击。要消除设备旋转时视图仍然无法点击的错误,我们可以引入一个 boolean 变量,我们将在动画结束时将其设置为 true 并通过覆盖 onSaveInstanceState(outState: Bundle) 并在中恢复它来保留它onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) 并检查设备旋转到 re-enable 之前是否为 true 再次单击。