在通过导航组件添加到动作的动画完成之前,防止点击视图
Prevent views from being clicked until animation added to action via navigation component completes
给定 2 个片段 A
和 B
,A
移动到 B
(所以 A -> B
),通过带有输入动画的导航组件动作添加。如何防止 Fragment B
中的视图在进入动画 运行 时可点击?我发现了这个问题 How to add listener to android Navigation Architecture Component action animation 但不幸的是没有答案。
我在文档中发现,我可以通过挂接到 NavAction
的 NavOptions
对象获取该动画的资源 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
,它将是 exit
或 popEnter
,对于片段 B
,它将是 enter
或 popExit
。
视图被点击的问题发生在片段进入(enter
或popEnter
)时,所以可以使用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
再次单击。
给定 2 个片段 A
和 B
,A
移动到 B
(所以 A -> B
),通过带有输入动画的导航组件动作添加。如何防止 Fragment B
中的视图在进入动画 运行 时可点击?我发现了这个问题 How to add listener to android Navigation Architecture Component action animation 但不幸的是没有答案。
我在文档中发现,我可以通过挂接到 NavAction
的 NavOptions
对象获取该动画的资源 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
,它将是 exit
或 popEnter
,对于片段 B
,它将是 enter
或 popExit
。
视图被点击的问题发生在片段进入(enter
或popEnter
)时,所以可以使用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
再次单击。