在Compose中隐藏软件键盘会破坏KotlinFlow/Channel事件收集

uqzxnwby  于 2023-01-26  发布在  Kotlin
关注(0)|答案(3)|浏览(209)

我正在尝试在一个带有Compose UI的Android应用中隐藏软键盘。ViewModel通过kotlin协程通道发出了一些事件:

private val _screenEvents = Channel<ScreenEvent>(capacity = Channel.UNLIMITED)
val screenEvents: Flow<ScreenEvent> = _screenEvents.receiveAsFlow()

事件按如下方式发送:

_screenEvents.trySend(event)

在"编写"屏幕中,事件收集在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,也会产生此问题。结果发现BottomSheet动画是可取消的,并且在这种情况下会抛出CancellationException。
最小、完整、可重现示例:https://gist.github.com/Alektas/e86e75a596cb20797f5c9acac238e24f

31moq8wy

31moq8wy1#

事实证明,BottomSheet动画是可取消的,并且当FocusManagerTextField清除焦点时抛出CancellationException

作为一个变通方案,我现在用try/catch来 Package 崩溃。如果有人能给出更好的解决这个问题的方法,我会很高兴的。

focusManager.clearFocus()
try {
    bottomSheetState.collapse()
} catch (e: Exception) {
    e.printStackTrace()
}
emeijp43

emeijp432#

目前,FlowCollector -bottomSheetState.collapseLaunchedEffect作用域中启动。因此,当折叠流收集器中发生异常时,LaunchedEffect作用域将被停用。

按如下所示尝试Composition CoroutineScope

val scope = rememberCoroutineScope()

LaunchedEffect(Unit) {
    viewModel.screenEvents
        .collect { event ->
            when (event) {
                is ScreenEvent.CollapseSearchResults -> {
                    // keyboard?.hide()
                    // inputService?.hideSoftwareKeyboard()
                    focusManager.clearFocus()
                    scope.launch { bottomSheetState.collapse() }
                }
                ...
            }
        }
}
u0njafvf

u0njafvf3#

这是更多关于re-composition它似乎,每当你的状态改变composer函数开始recomposition,LaunchEffectcoroutineContext将被取消和你的底部工作表显示/隐藏将得到中断.要解决这个问题,你可以尝试NonCancelable Job像下面

try {
                    sheetState.show()
                }finally {
                    withContext(NonCancellable){
                        sheetState.show()
                    }
                }

这里是参考链接运行不可取消的块

相关问题