Jetpack Compose - не дать сфокусированным элементам украсть пресс?

У меня есть некоторые элементы, которые находятся в фокусе на нижнем листе. Я хочу свернуть нижний лист при нажатии кнопки возврата системы, что достаточно просто:

        BackHandler(enabled = bottomSheetState.isExpanded) {
    scope.launch {
      bottomSheetState.collapse()
    }
  }

Проблема в том, что если элемент сфокусирован на нижнем листе, логика обратного обработчика запускается только после двойного нажатия кнопки возврата : один раз для удаления фокуса с элемента (выделенное текстовое поле) и еще раз для запуска коллапса.

Я пробовал использовать LocalFocusManager.current чтобы объединить очистку фокуса при нажатии кнопки возврата, но логика возврата не запускается, пока элемент уже не потерял фокус.

Я могу убрать фокус при свертывании, поэтому я предполагаю, что настоящая проблема заключается в том, чтобы дважды нажать назад, когда лист 1) виден и 2) имеет сфокусированный дочерний элемент.

Есть ли способ, чтобы сфокусированные элементы не вытесняли мою обратную логику?

1 ответ

Привет, @Carter. Я обнаружил проблему на официальном трекере. Ссылку найти можноздесь . Это было исправлено в compose 1.1.0-alpha03, но поскольку библиотека является альфа-кандидатом, я не знаю, насколько она безопасна для производства. Существует также обходной путь упоминается здесь

более чистый подход:

  1. Создать этого менеджера
      /***
 * Compose issue to be fixed in alpha 1.03
 * track from here : https://issuetracker.google.com/issues/192433071?pli=1
 * current work around
 */
class KeyBoardManager(context: Context) {

    private val activity = context as Activity
    private var keyboardDismissListener: KeyboardDismissListener? = null

    private abstract class KeyboardDismissListener(
        private val rootView: View,
        private val onKeyboardDismiss: () -> Unit
    ) : ViewTreeObserver.OnGlobalLayoutListener {
        private var isKeyboardClosed: Boolean = false
        override fun onGlobalLayout() {
            val r = Rect()
            rootView.getWindowVisibleDisplayFrame(r)
            val screenHeight = rootView.rootView.height
            val keypadHeight = screenHeight - r.bottom
            if (keypadHeight > screenHeight * 0.15) {
                // 0.15 ratio is right enough to determine keypad height.
                isKeyboardClosed = false
            } else if (!isKeyboardClosed) {
                isKeyboardClosed = true
                onKeyboardDismiss.invoke()
            }
        }
    }

    fun attachKeyboardDismissListener(onKeyboardDismiss: () -> Unit) {
        val rootView = activity.findViewById<View>(android.R.id.content)
        keyboardDismissListener = object : KeyboardDismissListener(rootView, onKeyboardDismiss) {}
        keyboardDismissListener?.let {
            rootView.viewTreeObserver.addOnGlobalLayoutListener(it)
        }
    }

    fun release() {
        val rootView = activity.findViewById<View>(android.R.id.content)
        keyboardDismissListener?.let {
            rootView.viewTreeObserver.removeOnGlobalLayoutListener(it)
        }
        keyboardDismissListener = null
    }
}
  1. Создать этот составной
      @Composable
fun AppKeyboardFocusManager() {
    val context = LocalContext.current
    val focusManager = LocalFocusManager.current
    DisposableEffect(key1 = context) {
        val keyboardManager = KeyBoardManager(context)
        keyboardManager.attachKeyboardDismissListener {
            focusManager.clearFocus()
        }
        onDispose {
            keyboardManager.release()
        }
    }
}
  1. Подать заявку на уровне приложения
      setContent {
        AppKeyboardFocusManager()
        YourAppMaterialTheme {
            ...
        }
    }
Другие вопросы по тегам