隐藏软件键盘在撰写中违反Kotlin流/频道事件收集
我正在尝试使用 Compose UI 隐藏 Android 应用程序中的软键盘。 ViewModel 通过 kotlin 协程通道发出一些事件:
private val _screenEvents = Channel<ScreenEvent>(capacity = Channel.UNLIMITED)
val screenEvents: Flow<ScreenEvent> = _screenEvents.receiveAsFlow()
事件的发送方式如下:
_screenEvents.trySend(event)
在 Compose 屏幕中,事件在 LaunchedEffect 中收集,任何隐藏键盘的方法都只能工作一次,不会收集连续的事件。
val keyboard = LocalSoftwareKeyboardController.current
val inputService = LocalTextInputService.current
val focusManager = LocalFocusManager.current
LaunchedEffect(Unit) {
viewModel.screenEvents
.collect { event ->
when (event) {
is ScreenEvent.CollapseSearchResults -> {
// keyboard?.hide()
// inputService?.hideSoftwareKeyboard()
focusManager.clearFocus()
bottomSheetState.collapse()
}
...
}
}
}
TextField(value = "") {}
但如果我像这样交换线路:
bottomSheetState.collapse()
// keyboard?.hide()
// inputService?.hideSoftwareKeyboard()
focusManager.clearFocus()
一切都可以根据需要多次正常工作。但是折叠底板和隐藏键盘的动画是连续的,它不适合我。
有人可以向我解释一下问题是什么以及如何解决它吗?
编辑
如果 UI 中的 TextField 具有焦点并且显示软键盘,则会产生此问题。如果用户在动画播放时按住 BottomSheet,则效果相同。事实证明,BottomSheet 动画是可以取消的,并且在这种情况下会抛出 CancellationException。
最小、完整、可重现的示例: https://gist.github.com/Alektas/e86e75a596cb20797f5c9acac238e24f
I'm trying to hide the soft keyboard in an Android app with Compose UI.
There are events emitted by ViewModel through the kotlin coroutines channel:
private val _screenEvents = Channel<ScreenEvent>(capacity = Channel.UNLIMITED)
val screenEvents: Flow<ScreenEvent> = _screenEvents.receiveAsFlow()
Events are send like this:
_screenEvents.trySend(event)
In Compose screen, events are collected in LaunchedEffect and any way to hide keyboard only works once, consecutive events are not collected.
val keyboard = LocalSoftwareKeyboardController.current
val inputService = LocalTextInputService.current
val focusManager = LocalFocusManager.current
LaunchedEffect(Unit) {
viewModel.screenEvents
.collect { event ->
when (event) {
is ScreenEvent.CollapseSearchResults -> {
// keyboard?.hide()
// inputService?.hideSoftwareKeyboard()
focusManager.clearFocus()
bottomSheetState.collapse()
}
...
}
}
}
TextField(value = "") {}
But if I swap the lines like this:
bottomSheetState.collapse()
// keyboard?.hide()
// inputService?.hideSoftwareKeyboard()
focusManager.clearFocus()
Everything works fine as many times as necessary. But the animations of collapsing bottom sheet and hiding keyboard are sequential and it doesn't suit me.
Can someone explain to me what is the problem and how can I solve it?
Edit
This issue is produced if TextField in UI has focus and soft keyboard is shown. The same if user holds BottomSheet while it's animation. It's turned out that BottomSheet animation is cancellable and it throws CancellationException in this cases.
Minimal, complete, reproducible example: https://gist.github.com/Alektas/e86e75a596cb20797f5c9acac238e24f
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当前,FlowCollector -
BottomSheetState.Collapse
是在启动>启动
范围中启动的。因此,当崩溃流收集器中发生异常时,启动
范围被停用。尝试
构图CoroutinesCope
如下。Currently, FlowCollector -
bottomSheetState.collapse
is launch inLaunchedEffect
scope. thus, when an exception occurs in collapse flow collector,LaunchedEffect
scope is deactivated.Try
Composition CoroutineScope
as below.事实证明,当
FocusManager
从TextField
清除焦点时,BottomSheet
动画是可以取消的,并抛出CancellationException
作为一种解决方法,我现在用
try/catch
封装了折叠。如果有人提出更好的想法如何解决这个问题,我会很高兴。It's turned out that
BottomSheet
animations are cancellable and throwCancellationException
whenFocusManager
clears focus fromTextField
As a workaround, I've wrapped collapsing with
try/catch
for now. I'd be glad If someone showed a better idea how to solve this problem.这更多是关于重新组件的更多信息,每当您的状态更改构成函数开始重新组件时,
启动效果
coroutinecontext
将被取消,并且您的底部表show/hide将被中断。要解决此问题,您可以尝试不可变的工作,例如以下
是参考链接运行不可融合的块
it's more about re-composition it seems, whenever your state change compose function starts recomposing,
LaunchEffect
coroutineContext
will be canceled and your bottom sheet show/hide will get interrupted.to fix this you can try NonCancelable Job like following
here is the reference link Run non-cancellable block