Pantrix UI

Sayı alanı ve eylem tuşu

Compose Multiplatform'da sayı yazılan ve yazılınca bir şey yapan bir alanın iPhone'da neden gönderilemediği, bunun için kütüphanenin ne verdiği ve nasıl sınandığı. Sorun Pantrix'e özgü değildir: ortak kodunda KeyboardType.Number ile bir ImeAction isteyen her Compose Multiplatform projesinde aynı şekilde görülür.

Burada söylenenlerin hangisinin simülatörde görüldüğü, hangisinin Compose Multiplatform 1.12.1'in kaynağında okunduğu ve hangisinin doğrulanmadığı 7. bölümde ayrı ayrı yazılıdır.

1. Sorun

Belirti

Neden

iPhone'un sayı tuş takımı (UIKeyboardType.numberPad) bir PIN girmek için tasarlanmıştır ve bir return tuşu taşımaz. Compose, KeyboardType.Number isteyen alana iOS'ta bu tuş takımını verir. ImeAction, UIKit'te return tuşunun türüdür (returnKeyType); return tuşu olmayan bir klavyede gösterilecek yeri yoktur.

Yerli iOS uygulamaları bunu iki yoldan biriyle çözer: klavyenin üstüne "Bitti" düğmeli bir çubuk koyar (inputAccessoryView) ya da return tuşu olan bir klavye ister. Compose kendiliğinden ikisini de yapmaz.

2. Çözüm

iOS'ta, eylemi olan bir sayı için sayılar ve noktalama klavyesi istenir (UIKeyboardType.numbersAndPunctuation): rakamlarıyla açılır ve eylemi gösteren bir return tuşu vardır.

Compose bunun için bir yol verir: KeyboardOptions.platformImeOptions. iOS'taki PlatformImeOptions { keyboardType(…) }, klavyenin türünü UIKit'in kendi türüyle söyler ve KeyboardType'tan türetileni ezer.

API @ExperimentalComposeUiApi taşır ve kararlı bir karşılığı yoktur: Compose'un KeyboardType'larından hiçbiri iOS'ta bu klavyeye çevrilmez (7. bölüm), PlatformImeOptions'ın kurucusundaki her ayar da aynı işareti taşır. Kütüphane ona tek bir dosyada, iosMain'de dayanır; herkese açık hiçbir imzada deneysel bir tür yoktur. Bir Compose yükseltmesinde imzası değişirse o dosya derlenmez, davranışı değişirse NumberKeyboardOnIosTest düşer. Klavyenin kendisi ancak simülatörde görülür: yükseltmeden sonra alan bir kez açılıp bakılır.

Üç ayrıntı:

AyrıntıNe yapılır
1O klavye yazı yazmak içindir: tuşlarının üstünde sözcük öneren bir çubuk gösterirautoCorrectEnabled = false: çubuk kalkar
2Aynı klavyede işaretler ve, bir basış ötede, harfler de vardırSayı olmayanı alan kendisi geri çevirir: InputTransformation
3Eylemi olmayan bir sayının (ImeAction.Default, ImeAction.None) sayı tuş takımında bir eksiği yokturOna dokunulmaz: iOS'ta da sayı tuş takımını alır

3. Pantrix ile

Kütüphane tek bir fonksiyon verir (com.pantrixui.foundation.platform):

public expect fun numberKeyboardOptions(
    imeAction: ImeAction = ImeAction.Default,
    decimal: Boolean = false
): KeyboardOptions

Android'de, masaüstünde ve web'de istenen tür ve eylemdir, fazlası değil. iOS'ta eylemi olan bir sayı için sayılar ve noktalama klavyesini ister, düzeltme kapalı. decimal = true, KeyboardType.Number yerine KeyboardType.Decimal ister.

val quantity = rememberTextFieldState()
PantrixTextField(
    state = quantity,
    label = "Adet",
    keyboardOptions = numberKeyboardOptions(ImeAction.Done),
    onKeyboardAction = { onQuantity(quantity.text.toString().toIntOrNull()) },
    inputTransformation = DigitsOnly
)

/** Rakam olmayan bir şey içeren değişikliği bütünüyle geri çevirir. */
private val DigitsOnly = InputTransformation {
    if (!asCharSequence().all { it.isDigit() }) revertAllChanges()
}

PantrixPageJump alanını bununla kurar. PantrixTextField'in keyboardOptions parametresi de buraya işaret eder.

4. Pantrix olmadan

Bir expect fonksiyonu ve platform başına bir karşılık.

4.1. Ortak kod (commonMain)

expect fun numberKeyboardOptions(
    imeAction: ImeAction = ImeAction.Default,
    decimal: Boolean = false
): KeyboardOptions

internal fun plainNumberKeyboardOptions(
    imeAction: ImeAction,
    decimal: Boolean
): KeyboardOptions = KeyboardOptions(
    keyboardType = if (decimal) KeyboardType.Decimal else KeyboardType.Number,
    imeAction = imeAction
)

4.2. iOS (iosMain)

@OptIn(ExperimentalComposeUiApi::class)
actual fun numberKeyboardOptions(
    imeAction: ImeAction,
    decimal: Boolean
): KeyboardOptions {
    val plain = plainNumberKeyboardOptions(imeAction, decimal)
    val needsAKey = imeAction != ImeAction.Default && imeAction != ImeAction.None
    return if (!needsAKey) {
        plain
    } else {
        plain.copy(
            autoCorrectEnabled = false,
            platformImeOptions = PlatformImeOptions { keyboardType(UIKeyboardTypeNumbersAndPunctuation) }
        )
    }
}

PlatformImeOptions ve keyboardType: androidx.compose.ui.text.input; UIKeyboardTypeNumbersAndPunctuation: platform.UIKit.

4.3. Öteki platformlar (androidMain, jvmMain, web)

actual fun numberKeyboardOptions(
    imeAction: ImeAction,
    decimal: Boolean
): KeyboardOptions = plainNumberKeyboardOptions(imeAction, decimal)

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

6. Test etmek

Bir test klavyeyi göremez; görebildiği, alanın klavyeden ne istediğidir.

Klavyenin gerçekten o tuşla açıldığı ve tuşun işi yaptığı yalnızca bir cihazda ya da simülatörde görülür. Sayı yazılan ve eylemi olan her yeni alan simülatörde açılmalıdır.

7. Doğrulama

Görülenler

Kaynakta okunanlar

Doğrulanmayanlar

8. Bu depoda nerede

NeNerede
Fonksiyon ve ortak yardımcısıui/foundation/src/commonMain/kotlin/com/pantrixui/foundation/platform/NumberKeyboard.kt
iOS karşılığıui/foundation/src/iosMain/kotlin/com/pantrixui/foundation/platform/NumberKeyboard.ios.kt
Öteki karşılıklaraynı pakette NumberKeyboard.android.kt, NumberKeyboard.jvm.kt, NumberKeyboard.web.kt
TestlerNumberKeyboardTest (commonTest), NumberKeyboardOnIosTest (iosTest)
Kullanan bileşenPantrixPageJump (ui/components/.../data/pagination/PageJump.kt)
DemoTextField sayfasında "Sayı alanı ve eylem tuşu"; Pagination sayfasında tablo ayağı