Oluşturulan Anlamsal Bilgiler

Beste, uygulamanızın kullanıcı arayüzünü tanımlar ve composable'lar çalıştırılarak oluşturulur. Beste, kullanıcı arayüzünüzü tanımlayan composable'lardan oluşan bir ağaç yapısıdır.

Beste'nin yanında, Anlamsal ağacı adı verilen paralel bir ağaç bulunur. Bu ağaçta, kullanıcı arayüzünüz Erişilebilirlik hizmetleri ve Test çerçevesi için anlaşılır şekilde alternatif bir şekilde açıklanmaktadır. Erişilebilirlik hizmetleri, uygulamayı belirli bir ihtiyacı olan kullanıcılara açıklamak için ağacı kullanır. Test çerçevesi, uygulamanızla etkileşim kurmak ve hakkında iddialarda bulunmak için bu bilgileri kullanır. Anlamsal ağaç, composable'larınızı çizme hakkında bilgi içermez ancak composable'larınızın anlamsal anlamları hakkında bilgi içerir.

Şekil 1. Tipik bir kullanıcı arayüzü hiyerarşisi ve anlambilim ağacı.

Uygulamanız, Compose temelindeki ve malzeme kitaplığındaki composable'lar ve değiştiricilerden oluşuyorsa Anlambilim ağacı sizin için otomatik olarak doldurulur ve oluşturulur. Ancak özel düşük seviye composable'lar eklerken bunların anlamlarını manuel olarak sağlamanız gerekir. Ayrıca ağacınızın ekrandaki öğelerin anlamını doğru veya tam olarak yansıtmadığı durumlar da olabilir. Bu durumda ağacı uyarlayabilirsiniz.

Örneğin, şu özel takvim composable:

2. Şekil. Seçilebilir gün öğelerine sahip özel bir takvim.

Bu örnekte, tüm takvim Layout composable kullanılarak ve doğrudan Canvas öğesine işaretlenerek tek bir düşük seviyeli composable olarak uygulanmıştır. Başka bir işlem yapmazsanız erişilebilirlik hizmetleri, composable'ın içeriği ve kullanıcının takvim içindeki seçimi hakkında yeterli bilgiyi alamaz. Örneğin, bir kullanıcı 17 sayısını içeren günü tıklarsa erişilebilirlik çerçevesi yalnızca tüm takvim denetimi için açıklama bilgilerini alır. Bu durumda, TalkBack erişilebilirlik hizmeti "Takvim"i veya daha da iyisi "Nisan Takvimi"ni duyurur ve kullanıcı hangi günün seçilmiş olduğunu merak eder. Bu composable'ı daha erişilebilir hale getirmek için anlamsal bilgileri manuel olarak eklemeniz gerekecek.

Anlamsal özellikler

Kullanıcı arayüzü ağacındaki bazı anlamsal anlamlara sahip olan tüm düğümlerin Anlambilim ağacında paralel bir düğümü vardır. Anlambilim ağacındaki düğüm, karşılık gelen composable'ın anlamını ileten özellikleri içerir. Örneğin, Textcomposable, text anlamsal özelliğini içerir çünkü bu composable'ın anlamıdır. Icon, metinde Icon öğesinin anlamını ileten bir contentDescription özelliği (geliştirici tarafından ayarlanırsa) içerir. Compose temel kitaplığı üzerine oluşturulan kompozisyonlar ve değiştiriciler ilgili özellikleri sizin için zaten ayarlar. İsteğe bağlı olarak, semantics ve clearAndSetSemantics değiştiricileriyle özellikleri kendiniz ayarlayabilir veya geçersiz kılabilirsiniz. Örneğin, bir düğüme özel erişilebilirlik işlemleri ekleyebilir, açılabilir bir öğe için alternatif bir durum açıklaması sağlayabilir veya composable belirli bir metnin başlık olarak değerlendirilmesi gerektiğini belirtebilirsiniz.

Anlambilim ağacını görselleştirmek için Düzen Denetleyici Aracı'nı veya testlerimizde printToLog() yöntemini kullanabiliriz. Bu işlem, Logcat'in içindeki mevcut Semantics ağacını yazdırır.

class MyComposeTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun MyTest() {
        // Start the app
        composeTestRule.setContent {
            MyTheme {
                Text("Hello world!")
            }
        }
        // Log the full semantics tree
        composeTestRule.onRoot().printToLog("MY TAG")
    }
}

Bu testin sonucu şu şekilde olur:

    Printing with useUnmergedTree = 'false'
    Node #1 at (l=0.0, t=63.0, r=221.0, b=120.0)px
     |-Node #2 at (l=0.0, t=63.0, r=221.0, b=120.0)px
       Text = '[Hello world!]'
       Actions = [GetTextLayoutResult]

Anlamsal özelliklerin, composable'ın anlamını iletmek için nasıl kullanıldığını görmek üzere bir örneğe göz atalım. Şimdi bir Switch düşünelim. Kullanıcıya şöyle görünür:

3. Şekil. "Açık" ve "Kapalı" durumundaki bir anahtar.

Bu öğenin anlamını açıklamak için şöyle diyebilirsiniz: "Bu, şu anda 'Açık' durumunda olan açma/kapatma özelliğine sahip bir öğe. Etkileşimde bulunmak için bu düğmeyi tıklayabilirsiniz."

Anlamsal özellikler tam olarak bu amaçla kullanılır. Bu Switch öğesinin anlamsal düğümü, Layout Inspector ile görselleştirildiği gibi aşağıdaki özellikleri içerir:

4. Şekil. Bir Switch composable'ın Anlambilim özelliklerini gösteren Layout Inspector.

Role, incelediğimiz öğenin türünü gösterir. StateDescription, "Açık" durumuna nasıl referans verilmesi gerektiğini açıklar. Varsayılan olarak bu, "Açık" kelimesinin yerelleştirilmiş bir halidir ancak bağlama göre daha spesifik (ör. "Etkin") hale getirilebilir. ToggleableState, Switch'in mevcut durumudur. OnClick özelliği, bu öğeyle etkileşimde bulunmak için kullanılan yöntemi referans alır. Anlamsal özelliklerin tam listesi için SemanticsProperties nesnesine göz atın. Yapılabilecek Erişilebilirlik İşlemlerinin tam listesi için SemanticsActions nesnesine göz atın.

Uygulamanızdaki her composable'ın anlamsal özelliklerini takip ederek birçok güçlü olasılığın önünü açarsınız. Birkaç örnek:

  • TalkBack, ekranda gösterilenleri sesli okumak için bu özellikleri kullanır ve kullanıcının ekranla sorunsuz bir şekilde etkileşimde bulunmasına olanak tanır. Anahtarımız için şöyle bir şey olabilir: "Açık; Anahtar; açmak/kapatmak için iki kez dokunun". Kullanıcı, Anahtar'ı kapatmak için ekranına iki kez dokunabilir.
  • Test çerçevesi, düğümleri bulmak, onlarla etkileşimde bulunmak ve iddialarda bulunmak için özellikleri kullanır. Switch'imiz için örnek bir test şöyle olabilir:
    val mySwitch = SemanticsMatcher.expectValue(
        SemanticsProperties.Role, Role.Switch
    )
    composeTestRule.onNode(mySwitch)
        .performClick()
        .assertIsOff()

Birleştirilmiş ve birleştirilmemiş Semantik ağacı

Daha önce belirtildiği gibi, kullanıcı arayüzü ağacındaki her composable, sıfır veya daha fazla semantik özelliğine sahip olabilir. Anlamsal özellik ayarlanmamış composable, Semantik ağacına dahil edilmez. Bu şekilde, Anlamsal ağacı yalnızca gerçekten anlamsal anlam içeren düğümleri içerir. Bununla birlikte, bazen ekranda gösterilenin doğru anlamını iletmek için belirli düğümlerin alt ağaçlarını birleştirmek ve bunları tek bir düğüm olarak ele almak da yararlıdır. Bu şekilde, her alt düğümle ayrı ayrı uğraşmak yerine bir düğüm kümesini bir bütün olarak değerlendirebiliriz. Genel bir kural olarak, bu ağaçtaki her düğüm Erişilebilirlik hizmetleri kullanılırken odaklanılabilir bir öğeyi temsil eder.

Böyle bir composable'a örnek olarak Button verilebilir. Düğmenin birden çok alt düğüm içermesine rağmen tek bir öğe olarak neye işaret ettiğini belirtmek istiyoruz:

Button(onClick = { /*TODO*/ }) {
    Icon(
        imageVector = Icons.Filled.Favorite,
        contentDescription = null
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
}

Anlamsal ağacımızda, Button'ın alt öğelerinin özellikleri birleştirilir ve Button, ağaçta tek bir yapraklı düğüm olarak sunulur:

Composable'lar ve değiştiriciler, Modifier.semantics (mergeDescendants = true) {} çağrısı yaparak alt öğelerinin semantik özelliklerini birleştirmek istediklerini belirtebilir. Bu özelliğin true olarak ayarlanması, anlambilim özelliklerinin birleştirilmesi gerektiğini gösterir. Button örneğimizde, Button composable dahili olarak bu semantics değiştiricisini içeren clickable değiştiricisini kullanır. Bu nedenle, Button'ın alt düğümleri birleştirilir. composable'ınızda birleştirme davranışını ne zaman değiştirmeniz gerektiği hakkında daha fazla bilgi edinmek için erişilebilirlik belgelerini okuyun.

Temel ve Materyal Oluşturma kitaplıklarındaki çeşitli değiştiriciler ve composable'lar bu özelliğe sahiptir. Örneğin, clickable ve toggleable değiştiricileri kendi alt öğelerini otomatik olarak birleştirir. Ayrıca ListItem composable, alt öğelerini de birleştirir.

Ağaç incelemesi

Anlambilim ağacı derken, aslında iki farklı ağaçtan bahsediyoruz. mergeDescendants, true olarak ayarlandığında alt düğümleri birleştiren birleştirilmiş bir Semantik ağacı vardır. Ayrıca, birleştirmeyi uygulamayan ancak her düğümün değişmesini sağlayan birleştirilmiş bir anlamsal ağaç vardır. Erişilebilirlik hizmetleri birleştirilmiş ağacı kullanır ve mergeDescendants özelliğini dikkate alarak kendi birleştirme algoritmalarını uygular. Test çerçevesi varsayılan olarak birleştirilmiş ağacı kullanır.

Her iki ağacı da printToLog() yöntemiyle inceleyebilirsiniz. Varsayılan olarak ve önceki örneklerde olduğu gibi, birleştirilen ağaç günlüğe kaydedilir. Ayrılan ağacı yazdırmak için onRoot() eşleştiricinin useUnmergedTree parametresini true olarak ayarlayın:

composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")

Düzen İnceleyici, görünüm filtresinde tercih edilen ağacı seçerek hem birleştirilmiş hem de ayrılmamış anlam ağacını görüntülemenize olanak tanır:

5. Şekil. Hem birleştirilmiş hem de ayrılmış Anlamsal ağacın görüntülenmesine olanak tanıyan Düzen İnceleyici görünüm seçenekleri.

Düzen İnceleyici, ağacınızdaki her bir düğüm için özellikler panelinde o düğümde ayarlanmış olan Birleştirilmiş Anlamları ve Anlamları gösterir.

Test Çerçevesi'ndeki eşleştiriciler, varsayılan olarak birleştirilmiş Anlambilim ağacını kullanır. Bu yüzden içinde gösterilen metni eşleştirerek bir Düğmeyle etkileşimde bulunabilirsiniz:

composeTestRule.onNodeWithText("Like").performClick()

Daha önce onRoot eşleştiricide yaptığımız gibi eşleştiricilerin useUnmergedTree parametresini true değerine ayarlayarak bu davranışı geçersiz kılabilirsiniz.

Birleştirme davranışı

Bir composable, alt öğelerinin birleştirilmesi gerektiğini belirttiğinde bu birleştirme işlemi tam olarak nasıl gerçekleşir?

Her anlambilim mülkünün tanımlanmış bir birleştirme stratejisi vardır. Örneğin, ContentDescription özelliği, tüm alt ContentDescription değerlerini bir listeye ekler. Bir anlambilim mülkünün birleştirme stratejisini, SemanticsProperties.kt içinde mergePolicy uygulamasını kontrol ederek kontrol edebilirsiniz. Mülkler her zaman üst veya alt değeri seçmeyi, değerleri bir liste veya dizede birleştirmeyi, birleştirmeye izin vermemeyi ve bunun yerine bir istisna atamayı ya da başka bir özel birleştirme stratejisini kullanmayı seçebilir.

Önemli bir not, kendilerinin ayarladıkları mergeDescendants = true alt öğelerinin birleştirmeye dahil edilmemesidir. Bir örnekle açıklayalım:

6. Şekil. Resim, metin ve yer işareti simgesi içeren liste öğesi.

Burada tıklanabilir bir liste öğesi var. Kullanıcı satıra bastığında uygulama, kullanıcının makaleyi okuyabileceği makale ayrıntıları sayfasına gider. Liste öğesinin içinde, bu makaleye yer işareti koymak için bir düğme bulunmaktadır. Bu örnekte, iç içe yerleştirilmiş bir tıklanabilir öğemiz vardır. Böylece düğme, birleştirilmiş ağaçta ayrı olarak görünecektir. Bu satırdaki içeriğin geri kalanı birleştirilir:

7. Şekil. Birleştirilmiş ağaç, Satır düğümünün içindeki bir listede birden çok metin içeriyor. Ayrılmış ağaç, composable'ın (Metin) her biri için ayrı düğümler içerir.

Anlambilim ağacını uyarlama

Daha önce belirtildiği gibi, belirli anlamsal özellikleri geçersiz kılabilir veya temizleyebilir ya da ağacın birleştirme davranışını değiştirebilirsiniz. Bu, özellikle kendi özel bileşenlerinizi oluştururken geçerlidir. Doğru özellikleri ve birleştirme davranışını ayarlamazsanız uygulamanıza erişilemeyebilir ve testler beklediğinizden farklı davranabilir. Semantik ağacını uyarlamanız gereken bazı yaygın kullanım alanları hakkında daha fazla bilgi edinmek için erişilebilirlik belgelerini okuyun. Test hakkında daha fazla bilgi edinmek isterseniz Test Kılavuzu'na göz atın.