Pantrix UI

Klavyeyi kapatma

Compose Multiplatform'da bir alanın yazılım klavyesinin iPhone'da neden kapatılamadığı, kütüphanenin bunun için ne verdiği ve nasıl sınandığı. Sorun Pantrix'e özgü değildir: birkaç satırlık ya da sayı yazılan bir alanı olan her ekranda görülür.

1. Sorun

Ne görülür

2. Çözüm

Ekranın köküne, gösterdiği her şeyin altına bir dokunuş dinleyicisi konur. Altındaki hiçbir şeyin almadığı bir dokunuşta odağı bırakır (FocusManager.clearFocus()): alan odağını bırakır, klavye de onunla gider.

Basışı kim alır
KullanıcıComposeArdından
Bir düğmeye dokunuşDüğme alırİşini yapar; odak olduğu yerde kalır
Alana dokunuşAlan alırİmleç kayar; klavye kalır
Kaydıran bir sürüklemeKaydıran alırOdak kalır
Boş bir yere dokunuşHiçbir şey almazclearFocus(): klavye gider

3. Pantrix ile

Tek bir değiştirici, com.pantrixui.foundation.keyboard paketinde, ekranın ya da uygulamanın kökünde:

ClearFocusOnTap.kt

public fun Modifier.clearFocusOnTap(): Modifier

CommentScreen.kt

Column(Modifier.fillMaxSize().clearFocusOnTap()) {
    PantrixTextArea(state = comment, label = stringResource(Res.string.comment))
    PantrixButton(text = stringResource(Res.string.send), onClick = ::send)
}
iOS
Klavyeyi kapatmanın yolu.
Android
Sistemin geri hareketinin yanına bir yol.
Masaüstü ve web
Boş bir yere tıklamak, tarayıcıdaki gibi odağı bırakır.

4. Pantrix olmadan

pointerInput ve LocalFocusManager ile, ortak kodda bir değiştirici düğümü. Düğüm yazmak istemeyen bir proje aynısını bir composable'ın içinde yapar.

Bir değiştirici düğümü

fun Modifier.clearFocusOnTap(): Modifier = this then ClearFocusOnTapElement

private data object ClearFocusOnTapElement : ModifierNodeElement<ClearFocusOnTapNode>() {
    override fun create() = ClearFocusOnTapNode()
    override fun update(node: ClearFocusOnTapNode) = Unit
}

private class ClearFocusOnTapNode : DelegatingNode(), CompositionLocalConsumerModifierNode {
    init {
        delegate(SuspendingPointerInputModifierNode {
            detectTapGestures(onTap = { currentValueOf(LocalFocusManager).clearFocus() })
        })
    }
}

Bir composable'ın içinde

val focusManager = LocalFocusManager.current
Column(
    Modifier
        .fillMaxSize()
        .pointerInput(focusManager) { detectTapGestures(onTap = { focusManager.clearFocus() }) }
) {
    // ekranın içeriği
}

detectTapGestures androidx.compose.foundation.gestures paketindedir; düğümün tipleri androidx.compose.ui.node ve …ui.input.pointer paketlerinde.

5. Yardımcının yapmadıkları

Kaydırınca klavyeyi indirmez.
iOS'un keyboardDismissMode'unun burada karşılığı yoktur: kaydırmak odağı olduğu yerde bırakır.
Klavyenin üstüne bir “Bitti” çubuğu koymaz.
O, yerli iOS'un öteki yoludur (inputAccessoryView). Burada denenmedi.
Kendi penceresi olan bir katmanın dokunuşlarını duymaz.
Bir alan taşıyan Popup ya da Dialog değiştiriciyi kendi içeriğine de alır.
Odağı alan bir düğmeden odağı geri almaz.
Masaüstünde ve web'de basılan bir düğme odağı kendisi alabilir: bu düğmenin işidir.

6. Test etmek

Beş hedefte bir birim testi

ClearFocusOnTapTest: boş bir yere dokunuş odağı alır; alana parmakla ya da fareyle dokunuş odağı tutar; odak almayan bir düğme işini yapar; kaydıran bir sürükleme odağı tutar.

Maestro'da hideKeyboard'un yerine

Kökünde değiştirici olan bir ekranda boş bir yere dokunan bir adım aynısını yapar.

- tapOn: "A note for the courier"  # boş yer: klavye gider
- tapOn:
    id: "Send"

Klavyenin gerçekten gittiği yalnızca bir cihazda ya da bir simülatörde görülür.

7. Doğrulama

Simülatörde, emülatörde ve web'de görüldü

Kaynaklarda okundu

Denetlenmedi

8. Depoda nerede

Değiştiricifoundation/keyboard/ClearFocusOnTap.kt
TestlerClearFocusOnTapTest, commonTest içinde
Kim kullanırDemo uygulamasının kökü; PantrixTextArea ve PantrixFilledTextArea onu anar
DemoText Area sayfasındaki “Dışarıya dokunmak klavyeyi kapatır” örneği