Varsayılan olarak, bir Compose uygulamasındaki erişilebilirlik ekran okuyucu davranışı, beklenen okuma sırasına göre uygulanır. Bu genellikle soldan sağa, daha sonra yukarıdan aşağıya doğru olur.
Ancak algoritmanın ek ipuçları olmadan gerçek okuma sırasını belirleyemediği bazı uygulama düzeni türleri de vardır. Görünüme dayalı uygulamalarda, bu sorunları traversalBefore
ve traversalAfter
özelliklerini kullanarak düzeltebilirsiniz.
Compose 1.5'ten itibaren Compose da aynı ölçüde esnek bir API sunar ancak yeni bir kavramsal model sunar.
isTraversalGroup
ve traversalIndex
, varsayılan sıralama algoritmasının uygun olmadığı senaryolarda erişilebilirliği ve TalkBack odak sırasını kontrol etmenize olanak tanıyan semantik özelliklerdir. isTraversalGroup
anlam açısından önemli grupları tanımlarken traversalIndex
, bu gruplar içindeki bağımsız öğelerin sırasını ayarlar. isTraversalGroup
tek başına veya daha fazla özelleştirme için traversalIndex
ile kullanılabilir.
Ekran okuyucu geçiş sırasını kontrol etmek için uygulamanızda isTraversalGroup
ve traversalIndex
kullanın.
Öğeleri isTraversalGroup
ile gruplandır
isTraversalGroup
, bir anlamsal düğümünün bir geçiş grubu olup olmadığını tanımlayan bir boole özelliğidir. Bu düğüm türü, düğümün alt öğelerini düzenlerken işlevi sınır veya sınır görevi görecek düğümdür.
Bir düğümde isTraversalGroup = true
politikasının ayarlanması, o düğümün tüm alt öğelerinin diğer öğelere geçmeden önce ziyaret edildiği anlamına gelir. isTraversalGroup
öğesini; Sütunlar, Satırlar veya Kutular gibi ekran okuyucu dışındaki odaklanılabilir düğümlerde ayarlayabilirsiniz.
Aşağıdaki örnekte isTraversalGroup
kullanılmıştır. Dört metin öğesi yayar. Soldaki iki öğe bir CardBox
öğesine, sağdaki iki öğe ise başka bir CardBox
öğesine aittir:
// CardBox() function takes in top and bottom sample text. @Composable fun CardBox( topSampleText: String, bottomSampleText: String, modifier: Modifier = Modifier ) { Box(modifier) { Column { Text(topSampleText) Text(bottomSampleText) } } } @Composable fun TraversalGroupDemo() { val topSampleText1 = "This sentence is in " val bottomSampleText1 = "the left column." val topSampleText2 = "This sentence is " val bottomSampleText2 = "on the right." Row { CardBox( topSampleText1, bottomSampleText1 ) CardBox( topSampleText2, bottomSampleText2 ) } }
Bu kod aşağıdakine benzer bir çıkış üretir:
Hiçbir semantik ayarlanmadığı için ekran okuyucunun varsayılan davranışı, öğeleri soldan sağa ve yukarıdan aşağıya kaydırmaktır. Bu varsayılan ayar nedeniyle TalkBack, cümle parçalarını yanlış sırada okur:
"Bu cümle şuradadır:" → "Bu cümle" → "sol sütun". → "sağ tarafta".
Parçaları doğru şekilde sıralamak için orijinal snippet'i isTraversalGroup
değerini true
olacak şekilde değiştirin:
@Composable fun TraversalGroupDemo2() { val topSampleText1 = "This sentence is in " val bottomSampleText1 = "the left column." val topSampleText2 = "This sentence is" val bottomSampleText2 = "on the right." Row { CardBox( // 1, topSampleText1, bottomSampleText1, Modifier.semantics { isTraversalGroup = true } ) CardBox( // 2, topSampleText2, bottomSampleText2, Modifier.semantics { isTraversalGroup = true } ) } }
isTraversalGroup
özellikle her CardBox
için ayarlandığından öğeleri sıralarken CardBox
sınırları uygulanır. Bu durumda, önce soldaki CardBox
, ardından sağ CardBox
okunur.
TalkBack artık cümle parçalarını doğru sırada okuyor:
"Bu cümle" → "sol sütunda". → "Bu cümle" → "sağ taraftadır."
Geçiş sırasını daha fazla özelleştirin
traversalIndex
, TalkBack geçiş sırasını özelleştirmenize olanak tanıyan bir kayan özelliktir. Öğelerin birlikte gruplandırılması TalkBack'in düzgün çalışması için yeterli değilse ekran okuyucu sıralamasını daha da özelleştirmek için isTraversalGroup
ile birlikte traversalIndex
kullanın.
traversalIndex
özelliği aşağıdaki özelliklere sahiptir:
- İlk olarak,
traversalIndex
değerleri daha düşük olan öğelere öncelik verilir. - Pozitif veya olumsuz olabilir.
- Varsayılan değer
0f
değeridir. - Yalnızca metin veya düğmeler gibi ekrandaki öğeler gibi ekran okuyucuya odaklanılabilir düğümleri etkiler. Örneğin, bir sütunda yalnızca
traversalIndex
değerinin ayarlanması (sütun için deisTraversalGroup
değeri ayarlanmadıkça) herhangi bir etkisi olmaz.
Aşağıdaki örnekte traversalIndex
ve isTraversalGroup
özelliklerini birlikte nasıl kullanabileceğiniz gösterilmektedir.
Örnek: Çapraz saat kadranı
Saat kadranı, standart geçiş sıralamasının çalışmadığı yaygın bir senaryodur. Bu bölümdeki örnek, kullanıcının saat kadranındaki sayılar arasında gezinip saat ve dakika aralıkları için rakamları seçebileceği bir zaman seçicidir.
Aşağıdaki basitleştirilmiş snippet'te, 12 ile başlayan ve çember etrafında saat yönünde hareket eden 12 rakamın çizildiği bir CircularLayout
vardır:
@Composable fun ClockFaceDemo() { CircularLayout { repeat(12) { hour -> ClockText(hour) } } } @Composable private fun ClockText(value: Int) { Box(modifier = Modifier) { Text((if (value == 0) 12 else value).toString()) } }
Saat kadranı varsayılan soldan sağa ve yukarıdan aşağıya sıralamayla mantıklı bir şekilde okunmadığından, TalkBack sayıları sırayla okur. Bu durumu düzeltmek için aşağıdaki snippet'te gösterildiği gibi artan sayaç değerini kullanın:
@Composable fun ClockFaceDemo() { CircularLayout(Modifier.semantics { isTraversalGroup = true }) { repeat(12) { hour -> ClockText(hour) } } } @Composable private fun ClockText(value: Int) { Box(modifier = Modifier.semantics { this.traversalIndex = value.toFloat() }) { Text((if (value == 0) 12 else value).toString()) } }
Geçiş sırasını doğru şekilde ayarlamak için önce CircularLayout
grubunu bir geçiş grubu yapın ve isTraversalGroup = true
değerini ayarlayın. Ardından, her saat metni düzene çizilirken karşılık gelen traversalIndex
değerini sayaç değerine ayarlayın.
Sayaç değeri sürekli olarak arttığı için her saat değerinin traversalIndex
değeri, ekrana sayı eklendikçe büyür. Saat değeri 0'ın traversalIndex
değeri 0, saat değeri 1'in traversalIndex
değeri ise 1 olur.
Bu şekilde, TalkBack'in mesajları okuyacağı sıra ayarlanır. Artık CircularLayout
içindeki sayılar beklenen sırada okunur.
Ayarlanan traversalIndexes
yalnızca aynı gruplandırma içindeki diğer dizinlere göre olduğundan ekran sıralamasının geri kalanı korunmuştur. Başka bir deyişle, önceki kod snippet'inde gösterilen anlamsal değişiklikler yalnızca isTraversalGroup = true
öğesinin ayarlandığı saat kadranındaki sıralamayı değiştirir.
CircularLayout's
semantiği isTraversalGroup =
true
olarak ayarlanmazsa traversalIndex
değişikliklerinin geçerli olmaya devam edeceğini unutmayın. Ancak bu işlemleri bağlayabileceğiniz CircularLayout
olmadığında saat kadranının on iki basamağı, ekrandaki diğer tüm öğeler ziyaret edildikten sonra en son okunur. Bunun nedeni, diğer tüm öğelerin varsayılan traversalIndex
değerinin 0f
olması ve saat metin öğelerinin diğer tüm 0f
öğelerinden sonra okunmasıdır.
Örnek: Kayan işlem düğmesi için geçiş sırasını özelleştirme
Bu örnekte traversalIndex
ve isTraversalGroup
, Materyal Tasarım kayan işlem düğmesinin (FAB) geçiş sıralamasını kontrol eder. Bu örneğin temeli aşağıdaki düzendir:
Varsayılan olarak, bu örnekteki düzen TalkBack sıralamasına sahiptir:
Üst Uygulama Çubuğu → 0-6 arası örnek metinler → kayan işlem düğmesi (FAB) → Alt Uygulama Çubuğu
Ekran okuyucunun önce FAB'a odaklanmasını isteyebilirsiniz. FAB gibi bir Materyal öğesinde traversalIndex
ayarlamak için aşağıdakileri yapın:
@Composable fun FloatingBox() { Box(modifier = Modifier.semantics { isTraversalGroup = true; traversalIndex = -1f }) { FloatingActionButton(onClick = {}) { Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon") } } }
Bu snippet'te, isTraversalGroup
değeri true
olarak ayarlanmış bir kutu oluşturup aynı kutu için bir traversalIndex
değeri belirlemek (-1f
, 0f
olan varsayılan değerden daha düşüktür) kayan kutunun diğer tüm ekrandaki öğelerden önce geldiği anlamına gelir.
Daha sonra, kayan kutuyu ve diğer öğeleri bir yapıya yerleştirebilirsiniz. Bu yapı, Materyal Tasarım düzeni uygular:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun ColumnWithFABFirstDemo() { Scaffold( topBar = { TopAppBar(title = { Text("Top App Bar") }) }, floatingActionButtonPosition = FabPosition.End, floatingActionButton = { FloatingBox() }, content = { padding -> ContentColumn(padding = padding) }, bottomBar = { BottomAppBar { Text("Bottom App Bar") } } ) }
TalkBack, öğelerle aşağıdaki sırada etkileşime geçer:
FAB → Üst Uygulama Çubuğu → 0'dan 6'ya kadar örnek metinler → Alt Uygulama Çubuğu
Ek kaynaklar
- Erişilebilirlik: Tüm Android uygulama geliştirmelerinde ortak olan temel kavramlar ve teknikler
- Erişilebilir Uygulamalar Derleme: Uygulamanızı daha erişilebilir hale getirmek için atabileceğiniz temel adımlar
- Uygulama erişilebilirliğini iyileştirme ilkeleri: Uygulamanızı daha erişilebilir hale getirmeye çalışırken unutulmaması gereken temel ilkeler
- Erişilebilirlik için test etme: Android erişilebilirliği için test ilkeleri ve araçları