Bazen ekranınızdaki öğelerin varsayılan odak davranışını geçersiz kılmanız gerekir. Örneğin, composable'ları gruplandırmak, belirli bir composable'a odaklanmayı önlemek, tek bir composable'a açıkça odaklanmayı istemek, yakalama ya da odağı serbest bırakmak veya giriş ya da çıkışta odağı yeniden yönlendirmek isteyebilirsiniz. Bu bölümde, varsayılan ayarlar ihtiyacınız olmadığında odak davranışının nasıl değiştirileceği açıklanmaktadır.
Odak gruplarıyla tutarlı gezinme sağlama
Bazen Jetpack Compose, sekmeli gezinme için bir sonraki doğru öğeyi hemen tahmin etmez. Özellikle de sekmeler ve listeler gibi karmaşık üst Composables
öğeleri devreye girdiğinde.
Odak araması genellikle Composables
bildirim sırasını takip etse de hiyerarşideki Composables
değerlerinden birinin tam olarak görünmeyen yatay kaydırılabilir olması gibi bazı durumlarda bu mümkün değildir. Bu, aşağıdaki örnekte gösterilmektedir.
Jetpack Compose, tek yönlü gezinme için beklediğiniz yoldan devam etmek yerine aşağıda gösterildiği gibi ekranın başlangıcına en yakın olan bir sonraki öğeye odaklanmaya karar verebilir:
Bu örnekte, geliştiricilerin odak noktasının Çikolatalar sekmesinden aşağıdaki ilk resme atlamak ve ardından Pastalar sekmesine geri dönmek istemediği açıkça görülmektedir. Bunun yerine, son sekmeye kadar sekmelerde çalışmaya ve daha sonra bu sekmenin içinde yer alan içeriğe odaklanmayı istiyorlardı:
Bir önceki örnekteki Sekme satırında olduğu gibi, bir composable grubunun sıralı olarak odaklanmasının önemli olduğu durumlarda, Composable
öğesini focusGroup()
değiştiricisine sahip bir üst öğenin içine kaydırmanız gerekir:
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, belirli bir yön için en yakın composable'ı arar. Başka bir gruptaki bir öğe, geçerli grupta tam olarak görünür olmayan bir öğeye daha yakınsa gezinme en yakın olanı seçer. Böyle bir davranıştan kaçınmak için focusGroup()
değiştiricisini uygulayabilirsiniz.
FocusGroup
, tüm grubun odak açısından tek bir varlık gibi görünmesini sağlar ancak odağı grubun kendisi almaz. Bunun yerine, en yakın alt öğe odaklanır. Bu şekilde, gezinme gruptan ayrılmadan önce tam olarak görünür olmayan öğeye gitmeyi bilir.
Bu durumda üç FilterChip
örneğine, SweetsCards
kullanıcı tamamen görünürken ve bazı FilterChip
gizlenmiş olsa bile SweetsCard
öğeden önce odaklanılır. Bunun nedeni, focusGroup
değiştiricisinin odak yöneticisine öğelerin odaklanılacağı sırayı ayarlamasını sağlayarak gezinmenin daha kolay ve kullanıcı arayüzü ile daha tutarlı olmasını sağlamasıdır.
focusGroup
değiştiricisi kullanılmadığında, FilterChipC
görünür olmasaydı odak gezinmesi bu öğeyi en son seçer. Bununla birlikte, böyle bir değiştirici eklemek yalnızca bulunabilir değil, aynı zamanda kullanıcıların beklediği gibi FilterChipB
sonrasında odaklanmayı da edinir.
Bir composable'ı odaklanılabilir hale getirme
Düğme veya clickable
değiştiricisine sahip bir composable gibi bazı composable'lar tasarım gereği odaklanabilir. Bir composable'a özellikle odaklanılabilir davranış eklemek istiyorsanız focusable
değiştiricisini kullanabilirsiniz:
var color by remember { mutableStateOf(Green) } Box( Modifier .background(color) .onFocusChanged { color = if (it.isFocused) Blue else Green } .focusable() ) { Text("Focusable 1") }
Bir composable'ı odaklanamaz hale getirmek
Öğelerinizden bazılarının odakta yer almaması gereken durumlar olabilir. Bu gibi nadir durumlarda, bir Composable
öğesinin odaklanmayı önlemek için canFocus property
özelliğinden yararlanabilirsiniz.
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, bir kullanıcı etkileşimine yanıt olarak açıkça odaklanma isteğinde bulunmak isteyebilirsiniz. Örneğin, kullanıcıya bir formu doldurmaya yeniden başlamak isteyip istemediğini sorabilir ve "evet"e bastığında bu formun ilk alanına yeniden odaklanmayı isteyebilirsiniz.
Yapmanız gereken ilk şey, bir FocusRequester
nesnesini klavye odağını taşımak istediğiniz composable ile ilişkilendirmektir. Aşağıdaki kod snippet'inde FocusRequester
nesnesi, Modifier.focusRequester
adlı bir değiştirici ayarlanarak TextField
ile ilişkilendirilir:
val focusRequester = remember { FocusRequester() } var text by remember { mutableStateOf("") } TextField( value = text, onValueChange = { text = it }, modifier = Modifier.focusRequester(focusRequester) )
Gerçek odak istekleri göndermek için FocusRequester'ın requestFocus
yöntemini çağırabilirsiniz. Bu yöntemi 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'te, düğme tıklandığında sistemden klavye odağını taşıması için nasıl istekte bulunulacağı gösterilmektedir:
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ğı yakalayıp serbest bırakın
Geçerli bir e-posta adresi veya telefon numarası almak gibi, uygulamanızın işlerini yapmak için ihtiyaç duyduğu doğru verileri (ör. geçerli bir e-posta adresi veya telefon numarası almak) sağlama konusunda kullanıcılarınıza rehberlik etmek için odaklanma özelliğinden yararlanabilirsiniz. Hata durumları kullanıcılarınıza ne olduğu konusunda bilgi verse de, hatalı bilgiler içeren alana, sorun düzeltilene kadar odaklanabilmek için ihtiyacınız olabilir.
Odağı yakalamak için captureFocus()
yöntemini çağırabilir ve daha sonra aşağıdaki örnekte olduğu gibi freeFocus()
yöntemini kullanarak serbest bırakabilirsiniz:
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 bir alt öğesi olan öğeler olarak görülebilir. Bu nedenle, bunları sıraladığınızda soldaki (veya üstte) her bir Modifier
, sağda (veya altında) takip eden Modifier
öğesini sarar. Bu, ikinci Modifier
öğesinin ilkinin içinde bulunduğu anlamına gelir. Böylece iki focusProperties
bildirilirken yalnızca en üsttekiler çalışır. Bunun nedeni, aşağıdakilerin en üstte yer almasıdır.
Kavramı daha iyi açıklamak için aşağıdaki koda bakın:
Modifier .focusProperties { right = item1 } .focusProperties { right = item2 } .focusable()
Bu durumda, önceki örnekte yer aldığı için item2
doğru odak noktasını gösteren focusProperties
kullanılmaz; dolayısıyla, item1
kullanılır.
Ebeveynler, bu yaklaşımdan yararlanarak FocusRequester.Default
özelliğini kullanarak bu davranışı varsayılan değere sıfırlayabilir:
Modifier .focusProperties { right = Default } .focusProperties { right = item1 } .focusProperties { right = item2 } .focusable()
Üst öğenin aynı değiştirici zincirinin parçası olması gerekmez. Bir üst composable, bir alt composable'ın odak özelliğinin üzerine yazabilir. Örneğin, düğmenin odaklanılamamasına neden olan şu FancyButton
öğesini düşünün:
@Composable fun FancyButton(modifier: Modifier = Modifier) { Row(modifier.focusProperties { canFocus = false }) { Text("Click me") Button(onClick = { }) { Text("OK") } } }
Kullanıcılar, canFocus
değerini true
olarak ayarlayarak bu düğmeyi tekrar odaklanabilir hale getirebilir:
FancyButton(Modifier.focusProperties { canFocus = true })
Her Modifier
gibi odakla ilgili olanlar da bildirdiğiniz sıraya göre farklı şekilde davranır. Örneğin, aşağıdaki gibi kod, Box
öğesini odaklanılabilir hale getirir ancak FocusRequester
, odaklanılabilir öğeden sonra bildirildiği için bu odaklanılabilir ile ilişkilendirilmez.
Box( Modifier .focusable() .focusRequester(Default) .onFocusChanged {} )
focusRequester
öğesinin, hiyerarşide altında bulunan ilk odaklanılan öğeyle ilişkilendirildiği unutulmamalıdır. Dolayısıyla bu focusRequester
, odaklanılabilir ilk alt öğeyi gösterir. Kullanılabilir alan yoksa herhangi bir yere işaret etmez.
Bununla birlikte, Box
odaklanılabilir olduğundan (focusable()
değiştiricisi sayesinde) iki yönlü gezinme kullanarak bu öğeye gidebilirsiniz.
Başka bir örnek vermek gerekirse onFocusChanged()
değiştiricisi, focusable()
veya focusTarget()
değiştiricilerinden sonra görünen ilk odaklanılabilir öğeye karşılık geldiğinden aşağıdakilerden biri işe yarar.
Box( Modifier .onFocusChanged {} .focusRequester(Default) .focusable() ) |
Box( Modifier .focusRequester(Default) .onFocusChanged {} .focusable() ) |
Giriş veya çıkışta odağı yönlendir
Bazen, aşağıdaki animasyonda gösterilene benzer çok spesifik bir gezinme türü sağlamanız gerekir:
Bunu nasıl oluşturabileceğinize geçmeden önce, odak aramasının varsayılan davranışını anlamak önemlidir. Herhangi bir değişiklik yapılmadan, odak araması Clickable 3
öğesine ulaştığında d-pad'de DOWN
tuşuna (veya eşdeğer ok tuşuna) basıldığında odak, Column
öğesinin altında görüntülenen öğeye taşınır, gruptan çıkılır ve sağdaki öğe yoksayılır. Odaklanabilir öğe yoksa odak herhangi bir yere taşınmaz ancak Clickable 3
üzerinde kalır.
Bu davranışı değiştirmek ve amaçlanan gezinmeyi sağlamak için, odak araması Composable
öğesine girdiğinde veya buradan çıktığında ne olacağını yönetmenize yardımcı olan focusProperties
değiştiricisini kullanabilirsiniz:
val otherComposable = remember { FocusRequester() } Modifier.focusProperties { exit = { focusDirection -> when (focusDirection) { Right -> Cancel Down -> otherComposable else -> Default } } }
Odağı, hiyerarşinin belirli bir bölümüne girdiğinde veya belirli bir bölümünden çıktığında belirli bir Composable
öğesine yönlendirmek mümkündür. Örneğin, kullanıcı arayüzünüzde iki sütun olduğunda ve ilk sütun işlenirken odak ikinciye geçtiğinden emin olmak istediğinizde:
Bu GIF'te, odak Column
1 öğesinde Clickable 3 Composable
değerine ulaştığında, odaklanılan bir sonraki öğe başka bir Column
öğesinde Clickable 4
olur. Bu davranış, focusProperties
değiştiricisinin içindeki focusDirection
ile enter
ve exit
değerleri birleştirilerek elde edilebilir. Her ikisinin de odağın geldiği yönü ve FocusRequester
döndüren bir lambdaya ihtiyacı vardır. Bu lambda üç farklı şekilde davranabilir: FocusRequester.Cancel
döndürülmesi odağın devam etmesini durdurur, ancak FocusRequester.Default
davranışını değiştirmez. Bunun yerine, başka bir Composable
öğesine ekli FocusRequester
sağlamak, odağı ilgili Composable
öğesine atlar.
Odaklanma yönünü değiştirme
Odağı bir sonraki öğeye veya belirli bir yöne doğru ilerletmek için onPreviewKey
değiştiricisinden yararlanabilir ve moveFocus
Değiştirici ile odağı ilerletmek için LocalFocusManager
işaretini ima edebilirsiniz.
Aşağıdaki örnekte odak mekanizmasının varsayılan davranışı gösterilmektedir: tab
tuşuna basıldığında odak, odak listesindeki bir sonraki öğeye ilerler. Bu, normalde yapılandırmanız gerekmese de, varsayılan çalışma biçimini değiştirebilmek için sistemin iç işleyişini bilmek önemlidir.
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 ilerletir.
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken görüntülenir
- Odaklanmak için tepki verin
- Oluşturma işleminde odaklan
- Odak geçişi sırasını değiştirme