Jetpack Compose 拦截软键盘的后退按钮

Thr*_*ian 4 android android-jetpack-compose

键盘打开时是否可以拦截后退按钮?使用 EditText 可以,如此处的答案所示,Compose 也可以吗?

我有一个Search可组合项,它在 300 毫秒去抖后调用搜索,当我单击后退按钮时,我不仅想要关闭键盘,还想要删除焦点并清除查询。

val focusManager = LocalFocusManager.current
val keyboardController = LocalSoftwareKeyboardController.current

val dispatcher: OnBackPressedDispatcher =
    LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher

val backCallback = remember {
    object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            if (!state.focused) {
                isEnabled = false
                Toast.makeText(context, "Back", Toast.LENGTH_SHORT).show()
                dispatcher.onBackPressed()
            } else {
                println("HomeScreen() Search Back ")
                state.query = TextFieldValue("")
                state.focused = false
                focusManager.clearFocus()
                keyboardController?.hide()
            }
        }
    }
}

DisposableEffect(dispatcher) { // dispose/relaunch if dispatcher changes
    dispatcher.addCallback(backCallback)
    onDispose {
        backCallback.remove() // avoid leaks!
    }
}
Run Code Online (Sandbox Code Playgroud)

只有在键盘关闭后才会触发向后搜索,如 gif 所示,它会在键盘关闭后进行另一次搜索,因为查询不为空。

注意,我不想要一个解决方案来阻止执行另一个查询,添加一个先前的查询检查可以做到这一点,我想拦截键盘后按,因此只有handleOnBackPressed当键盘打开时按下系统后退按钮而不是在键盘之后按下系统后退按钮时才会触发内部的块关闭了。

在此输入图像描述

SearchState

class SearchState<I, R, S>(
    initialResults: List<I>,
    suggestions: List<S>,
    searchResults: List<R>,
) {
    var query by mutableStateOf(TextFieldValue())
    var focused by mutableStateOf(false)
    var initialResults by mutableStateOf(initialResults)
    var suggestions by mutableStateOf(suggestions)
    var searchResults by mutableStateOf(searchResults)
    
    var searching by mutableStateOf(false)
    var searchInProgress = searching

    val searchDisplay: SearchDisplay
        get() = when {
            !focused && query.text.isEmpty() -> SearchDisplay.InitialResults
            focused && query.text.isEmpty() -> SearchDisplay.Suggestions
            searchInProgress -> SearchDisplay.SearchInProgress
            !searchInProgress && searchResults.isEmpty() -> SearchDisplay.NoResults
            else -> SearchDisplay.Results
        }

}
Run Code Online (Sandbox Code Playgroud)

并处理查询

LaunchedEffect(key1 = Unit) {
    snapshotFlow { state.query }
        .distinctUntilChanged()
        .filter {
            it.text.isNotEmpty()
        }
        .map {
            state.searching = false
            state.searchInProgress = true
            it
        }
        .debounce(300)
        .mapLatest {
            state.searching = true
            delay(300)
            viewModel.getTutorials(it.text)
        }
        .collect {
            state.searchInProgress = false
            state.searching = false
            state.searchResults = it
        }
}
Run Code Online (Sandbox Code Playgroud)

Ekn*_*ath 5

这是一个处理相同问题的扩展函数:

fun Modifier.onKeyboardDismiss(handleOnBackPressed: () -> Unit): Modifier = 
    composed {
    this.onPreInterceptKeyBeforeSoftKeyboard {
        if (it.key.keyCode == 17179869184) {
            handleOnBackPressed.invoke()
        }
        true
    }
}
Run Code Online (Sandbox Code Playgroud)

此功能已添加到最新版本的 Jetpack Compose 中。使用函数onPreInterceptKeyBeforeSoftKeyboard我只是拦截代码为17179869184的隐藏键盘按钮,并给出我自己的实现,用例是如果键盘被关闭则隐藏底部工作表,这满足了我的要求,找不到文档如果你们看到与此相关的内容,请在此处添加。谢谢