Odaklanma davranışını değiştirme

Bazen öğelerin varsayılan odaklanma davranışını geçersiz kılmak ekranda görebilirsiniz. Örneğin, composable'ları gruplandırmak, geliştirmelerin önlenmesi için belirli bir composable'a odaklanma, bire odaklanmayı isteme, odağı yakalama veya serbest bırakma ya da giriş veya çıkışta odağı yönlendirme. Bu bölümünde, varsayılan değerler istemediğinizde odak davranışını nasıl değiştireceğiniz açıklanmaktadır. gerekiyor.

Odak gruplarıyla tutarlı gezinme sağlayın

Bazen Jetpack Compose, sonraki öğe için doğru olanı hemen sekmeli gezinme, özellikle de sekmeler ve Composables gibi karmaşık üst öğeler olduğunda devreye girer.

Odaklı arama genellikle Composables bildirim sırasını takip etse de bazı durumlarda bu mümkün değildir. Örneğin, Composables hiyerarşi, tamamen görünür olmayan yatay bir kaydırılabilir öğedir. Bu bilginin gösterildiği yer: aşağıdaki örneğe bakın.

Jetpack Compose, öğenin başlangıcına en yakın olan bir sonraki öğeye odaklanmaya karar verebilir. aşağıdaki gösterildiği gibi, beklediğiniz yoldan devam etmek yerine tek yönlü gezinme:

Yatay üst gezinme menüsünü ve altındaki öğelerin listesini gösteren uygulama animasyonu.
Şekil 1. Üst yatay gezinmeyi ve aşağıdaki öğe listesini gösteren bir uygulama animasyonu
'nı inceleyin.

Bu örnekte, geliştiricilerin kasıtlı olmadığı açıkça bellidir: Çikolatalar sekmesinden aşağıdaki ilk resme geçin ve Pastalar sekmesi. Bunun yerine, odak noktası olana kadar sekmelerde son sekmeye geçip iç içeriğe odaklanın:

Yatay üst gezinme menüsünü ve altındaki öğelerin listesini gösteren uygulama animasyonu.
Şekil 2. Üst yatay gezinmeyi ve aşağıdaki öğe listesini gösteren bir uygulama animasyonu
'nı inceleyin.

Bir grup composable'a odaklanılmasının önemli olduğu durumlarda sırayla, önceki örnekteki Sekme satırında olduğu gibi, focusGroup() değiştiricisine sahip bir üst öğedeki Composable:

LazyVerticalGrid(columns = GridCells.Fixed(4)) {
    item(span = { GridItemSpan(maxLineSpan) }) {
        Row(modifier = Modifier.focusGroup()) {
            FilterChipA()
            FilterChipB()
            FilterChipC()
        }
    }
    items(chocolates) {
        SweetsCard(sweets = it)
    }
}

İki yönlü gezinme, verilen öğe için en yakın composable'ı yön: Başka bir gruptaki öğe, tamamen görünür olmayan bir öğeden daha yakınsa öğe geçerli grupta yer alıyorsa, gezinme en yakın öğeyi seçer. Bunu önlemek için focusGroup() değiştiricisini uygulayabilirsiniz.

FocusGroup, odak açısından tüm bir grubun tek bir varlık gibi görünmesini sağlar. ancak grup odakta kalmayan en yakın çocuk odaklanılır. Bu şekilde, gezinme, tamamen görünmeyen sayfalara gitmesini öğesine dokunun.

Bu durumda, üç FilterChip örneğine SweetsCard öğe, SweetsCards kullanıcı ve bazı FilterChip gizlenmiş olabilir. Bunun nedeni, focusGroup değiştiricisi, odak yöneticisine öğelerin gösterildiği sırayı ayarlamasını söyler Böylece, gezinmeyi kullanıcı arayüzüyle daha kolay ve tutarlı olacak şekilde odakladık.

focusGroup değiştiricisi kullanılmadığında, FilterChipC görünür değilse odaklan navigasyon en son onu seçer. Ancak böyle bir değiştirici eklemek, bulunabilir, ancak FilterChipB sonrasında odaklanmaya başlar, beklentiler yer alıyor.

Bir composable'ı odaklanılabilir hale getirme

Düğme veya composable gibi bazı composable'lara tasarım odaklı clickable değiştiricisi var. Özellikle eklemek istediğiniz odaklanma davranışını bir composable'a dönüştürmek için focusable değiştiricisini kullanırsınız:

var color by remember { mutableStateOf(Green) }
Box(
    Modifier
        .background(color)
        .onFocusChanged { color = if (it.isFocused) Blue else Green }
        .focusable()
) {
    Text("Focusable 1")
}

Bir composable'ı odaklanılamaz hale getirme

Öğelerinizden bazılarının katılmaması gereken durumlar olabilir. ön plana çıkarırım. Bu nadir durumlarda, canFocus property bir Composable öğesinin odaklanılabilir olmasını engeller.

var checked by remember { mutableStateOf(false) }

Switch(
    checked = checked,
    onCheckedChange = { checked = it },
    // Prevent component from being focused
    modifier = Modifier
        .focusProperties { canFocus = false }
)

FocusRequester ile klavye odağı iste

Bazı durumlarda belirli bir soruya yanıt olarak kullanıcı etkileşimi. Örneğin, bir kullanıcıya yeniden başlatmak isteyip istemediğini ya da "evet"e basarlarsa ilk alana yeniden odaklamak iletişim kurabilirsiniz.

İlk yapmanız gereken, bir FocusRequester nesnesini klavye odağını taşımak istediğiniz composable'ı seçin. Aşağıdaki kodda snippet'te bir FocusRequester nesne, bir TextField Modifier.focusRequester adlı değiştirici:

val focusRequester = remember { FocusRequester() }
var text by remember { mutableStateOf("") }

TextField(
    value = text,
    onValueChange = { text = it },
    modifier = Modifier.focusRequester(focusRequester)
)

Gerçek odaklanma istekleri göndermek için FocusRequester'ın requestFocus yöntemini çağırabilirsiniz. Bu yöntemi bir Composable bağlamı dışında çağırmanız gerekir (aksi takdirde, her yeniden oluşturmada yeniden yürütülür). Aşağıdaki snippet düğme açıkken klavye odağını hareket ettirmesi için sistemin nasıl istekte bulunulacağını gösterir tıklandı:

val focusRequester = remember { FocusRequester() }
var text by remember { mutableStateOf("") }

TextField(
    value = text,
    onValueChange = { text = it },
    modifier = Modifier.focusRequester(focusRequester)
)

Button(onClick = { focusRequester.requestFocus() }) {
    Text("Request focus on TextField")
}

Odağı yakala ve bırak

Kullanıcılarınızı uygulamanıza doğru verileri sağlamaları için yönlendirmek amacıyla odaktan yararlanabilirsiniz. görevini yerine getirmesi gerekiyorsa (örneğin, geçerli bir e-posta adresi veya telefon almak) sayı. Hata durumları kullanıcılarınızı neler olduğu konusunda bilgilendirse de alana kadar odaklanması için hatalı bilgi içeren alana düzeltildi.

Odağı yakalamak için captureFocus() yöntemini çağırabilir ve aşağıdaki gibi, bunun yerine freeFocus() yöntemiyle yayınlayın örnek:

val textField = FocusRequester()

TextField(
    value = text,
    onValueChange = {
        text = it

        if (it.length > 3) {
            textField.captureFocus()
        } else {
            textField.freeFocus()
        }
    },
    modifier = Modifier.focusRequester(textField)
)

Odak değiştiricilerin önceliği

Modifiers, yalnızca tek bir alt öğesi olan öğeler olarak görülebilir. Bu nedenle, sıraya soldaki (veya üstteki) her Modifier etiketi, sonraki URL'yi takip eden Modifier öğesini sağda (veya altında). Bu, ikinci Modifier öğesinin Böylece, iki focusProperties tanımlanırken yalnızca en üstteki ve aşağıdakilerden biri en üstte yer aldığından bir eser.

Kavramı daha iyi açıklamak için aşağıdaki kodu inceleyin:

Modifier
    .focusProperties { right = item1 }
    .focusProperties { right = item2 }
    .focusable()

Bu durumda, doğru odak noktası olarak item2 değerini gösteren focusProperties bir öncekinde bulunduğu için kullanılmamalıdır; dolayısıyla item1 bir tanesi kullanıldı.

Bu yaklaşımdan yararlanan bir ebeveyn de davranışı varsayılan olarak sıfırlayabilir FocusRequester.Default kullanılarak:

Modifier
    .focusProperties { right = Default }
    .focusProperties { right = item1 }
    .focusProperties { right = item2 }
    .focusable()

Üst öğenin aynı değiştirici zincirinin parçası olması gerekmez. Ebeveyn composable, bir alt composable'ın odak özelliğinin üzerine yazabilir. Örneğin, düğmenin odaklanılamamasına neden olan şu FancyButton dikkate alın:

@Composable
fun FancyButton(modifier: Modifier = Modifier) {
    Row(modifier.focusProperties { canFocus = false }) {
        Text("Click me")
        Button(onClick = { }) { Text("OK") }
    }
}

Kullanıcı, canFocus öğesini true olarak ayarlayarak bu düğmeyi tekrar odaklanabilir hale getirebilir:

FancyButton(Modifier.focusProperties { canFocus = true })

Her Modifier gibi odakla ilgili olanlar da sıraya göre farklı davranır açıklamanız gerekir. Örneğin, aşağıdaki gibi bir kod, Box odaklanılabilir, ancak FocusRequester bu odaklanılabilir öğe ile ilişkili değildir odaklanılabilir öğeden sonra tanımlanır.

Box(
    Modifier
        .focusable()
        .focusRequester(Default)
        .onFocusChanged {}
)

focusRequester öğesinin ilk odaklanılabilir; bu nedenle bu focusRequester, hedefe empatiyle yaklaşmak çok önemlidir. Bunların hiçbiri yoksa herhangi bir yere işaret etmez. Ancak Box odaklanılabilir olduğundan (focusable() değiştiricisi sayesinde), iki yönlü gezinmeyi kullanarak gidebilirsiniz.

Başka bir örnek olarak, aşağıdakilerden biri onFocusChanged() olarak kullanılabilir değiştiricisi, focusable() veya focusTarget() değiştiricileri.

Box(
    Modifier
        .onFocusChanged {}
        .focusRequester(Default)
        .focusable()
)
Box(
    Modifier
        .focusRequester(Default)
        .onFocusChanged {}
        .focusable()
)

Girişte veya çıkışta odağı yönlendir

Bazen, son derece özel bir gezinme türü sağlamanız gerekir. aşağıdaki animasyonda gösterildiği gibi:

Yan yana yerleştirilmiş iki düğme sütununu gösteren ve bir sütundan diğerine odaklanılan bir ekran animasyonu.
Şekil 3. Yan yana yerleştirilmiş ve bir sütundan diğerine odaklanılan iki düğme sütunu gösteren bir ekran animasyonu.
'nı inceleyin.

Bunun nasıl oluşturulacağına geçmeden önce, varsayılan olarak odaklı arama davranışının davranışını gösterir. Herhangi bir değişiklik yapılmadan, d-pad'de DOWN tuşuna (veya eşdeğeri) basarak Clickable 3 öğeye ulaşır ok tuşu) ise odağı Column sütununun altında görüntülenene taşır, ve sağdaki grubu yoksayabilirsiniz. Herhangi bir odaklanılabilir öğeler varsa, odak hiçbir yerde hareket etmez ancak Clickable 3

Bu davranışı değiştirmek ve amaçlanan gezinmeyi sağlamak için focusProperties değiştiricisi, odaklamaya odaklanıldığında ne olacağını yönetmenize yardımcı olur. araması Composable kodunu girer veya çıkar:

val otherComposable = remember { FocusRequester() }

Modifier.focusProperties {
    exit = { focusDirection ->
        when (focusDirection) {
            Right -> Cancel
            Down -> otherComposable
            else -> Default
        }
    }
}

Belirli bir Composable girildiğinde odak noktası bu noktaya yönlendirilebilir veya hiyerarşinin belirli bir bölümünden çıkar. Örneğin, kullanıcı arayüzünde iki sütuna giriyoruz ve ilk sütunun her işlenmesinde ikinci odaklamaya geçer:

Yan yana yerleştirilmiş iki düğme sütununu gösteren ve bir sütundan diğerine odaklanılan bir ekran animasyonu.
Şekil 4. Yan yana yerleştirilmiş ve bir sütundan diğerine odaklanılan iki düğme sütunu gösteren bir ekran animasyonu.
'nı inceleyin.

Bu GIF'te, odak Column 1'de Clickable 3 Composable hedefine ulaştığında, odaklanılan sonraki öğe başka bir Column içinde Clickable 4. Bu davranış focusDirection, enter ve exit ile birleştirilerek elde edilebilir focusProperties değiştiricisindeki değerler. İkisinin de lambdalara ihtiyacı var. parametresi olarak odağın nereden geldiğini gösterir ve FocusRequester Bu lambda üç farklı şekilde davranabilir: FocusRequester.Cancel, odaklanmaya devam etmeyi durdururken FocusRequester.Default, davranışını değiştirmez. Bunun yerine Başka bir Composable öğesine bağlı FocusRequester, odağı bu öğeye atlar belirli Composable.

Odak ilerleme yönünü değiştir

Odağı bir sonraki öğeye veya kesin bir yöne doğru ilerlemek için onPreviewKey değiştiricisinden yararlanıp LocalFocusManager moveFocus Değiştirici ile odağı geliştirebilirsiniz.

Aşağıdaki örnekte odak mekanizmasının varsayılan davranışı gösterilmektedir: tab tuşa basma algılandığında odak, odaktaki sonraki öğeye geçer liste'ye dokunun. Bu genellikle yapılandırmanız gereken bir şey olmasa da önemlidir varsayılan değerleri değiştirebilmek için sistemin iç işleyişini bilmek gösterir.

val focusManager = LocalFocusManager.current
var text by remember { mutableStateOf("") }

TextField(
    value = text,
    onValueChange = { text = it },
    modifier = Modifier.onPreviewKeyEvent {
        when {
            KeyEventType.KeyUp == it.type && Key.Tab == it.key -> {
                focusManager.moveFocus(FocusDirection.Next)
                true
            }

            else -> false
        }
    }
)

Bu örnekte, focusManager.moveFocus() işlevi odağı belirtilen öğeye veya işlev parametresinde belirtilen yöne doğru kullanılabilir.

ziyaret edin.