मर्ज करना और खाता मिटाना

सुलभता सेवाएं, स्क्रीन पर मौजूद एलिमेंट के बीच नेविगेट करती हैं. इसलिए, यह ज़रूरी है कि इन एलिमेंट को सही जानकारी के हिसाब से ग्रुप में बांटा जाए, अलग किया जाए या छिपाया जाए. जब आपकी स्क्रीन पर मौजूद हर लो-लेवल कंपोज़ेबल को अलग से हाइलाइट किया जाता है, तो उपयोगकर्ताओं को स्क्रीन पर एक जगह से दूसरी जगह जाने के लिए, बहुत ज़्यादा इंटरैक्ट करना पड़ता है. अगर एलिमेंट को बहुत ज़्यादा मर्ज किया जाता है, तो हो सकता है कि उपयोगकर्ताओं को यह समझ न आए कि कौनसे एलिमेंट लॉजिकल तौर पर एक साथ होने चाहिए. अगर स्क्रीन पर ऐसे एलिमेंट हैं जो सिर्फ़ सजावट के लिए हैं, तो उन्हें सुलभता सेवाओं से छिपाया जा सकता है. ऐसे मामलों में, सिमैंटिक को मर्ज करने, मिटाने, और छिपाने के लिए, Compose API का इस्तेमाल किया जा सकता है.

सिमैंटिक मर्ज करना

जब किसी पैरंट कंपोज़ेबल पर clickable मॉडिफ़ायर लागू किया जाता है, तो Compose उसके सभी चाइल्ड एलिमेंट को अपने-आप मर्ज कर देता है. यह समझने के लिए कि इंटरैक्टिव Compose मटीरियल और फ़ाउंडेशन कॉम्पोनेंट, डिफ़ॉल्ट रूप से मर्ज करने की रणनीतियों का इस्तेमाल कैसे करते हैं, इंटरैक्टिव एलिमेंट सेक्शन देखें.

आम तौर पर, किसी कॉम्पोनेंट में कई कंपोज़ेबल होते हैं. ये कंपोज़ेबल, एक लॉजिकल ग्रुप बना सकते हैं और हर एक में ज़रूरी जानकारी हो सकती है. हालांकि, हो सकता है कि आप सुलभता सेवाओं को उन्हें एक एलिमेंट के तौर पर देखने की अनुमति देना चाहें.

उदाहरण के लिए, किसी ऐसे कंपोज़ेबल के बारे में सोचें जो उपयोगकर्ता का अवतार, उसका नाम, और कुछ अतिरिक्त जानकारी दिखाता है:

यूज़र इंटरफ़ेस (यूआई) एलिमेंट का एक ग्रुप, जिसमें उपयोगकर्ता का नाम शामिल है. नाम चुना गया है.
पहली इमेज. यूज़र इंटरफ़ेस (यूआई) एलिमेंट का एक ग्रुप, जिसमें उपयोगकर्ता का नाम शामिल है. नाम चुना गया है.

सेमैंटिक मॉडिफ़ायर में mergeDescendants पैरामीटर का इस्तेमाल करके, Compose को इन एलिमेंट को मर्ज करने की अनुमति दी जा सकती है. इस तरह, सुलभता सेवाएं कॉम्पोनेंट को एक इकाई के तौर पर मानती हैं और डिसेंडेंट की सभी सिमैंटिक प्रॉपर्टी मर्ज हो जाती हैं:

@Composable
private fun PostMetadata(metadata: Metadata) {
    // Merge elements below for accessibility purposes
    Row(modifier = Modifier.semantics(mergeDescendants = true) {}) {
        Image(
            imageVector = Icons.Filled.AccountCircle,
            contentDescription = null // decorative
        )
        Column {
            Text(metadata.author.name)
            Text("${metadata.date} • ${metadata.readTimeMinutes} min read")
        }
    }
}

सुलभता सेवाएं अब पूरे कंटेनर पर एक साथ फ़ोकस करती हैं और उसके कॉन्टेंट को मर्ज करती हैं:

यूज़र इंटरफ़ेस (यूआई) एलिमेंट का एक ग्रुप, जिसमें उपयोगकर्ता का नाम शामिल है. सभी एलिमेंट एक साथ चुने जाते हैं.
दूसरी इमेज. यूज़र इंटरफ़ेस (यूआई) एलिमेंट का एक ग्रुप, जिसमें उपयोगकर्ता का नाम शामिल है. सभी एलिमेंट एक साथ चुने जाते हैं.

हर सिमैंटिक प्रॉपर्टी के लिए, मर्ज करने की रणनीति तय होती है. उदाहरण के लिए, ContentDescription प्रॉपर्टी, सभी डिसेंडेंट ContentDescription वैल्यू को एक सूची में जोड़ती है. सेमैंटिक प्रॉपर्टी को मर्ज करने की रणनीति देखने के लिए, SemanticsProperties.kt में mergePolicy को लागू करने का तरीका देखें. प्रॉपर्टी, पैरंट या चाइल्ड वैल्यू ले सकती हैं. साथ ही, वैल्यू को किसी सूची या स्ट्रिंग में मर्ज कर सकती हैं. इसके अलावा, मर्ज करने की अनुमति न देकर, गड़बड़ी का मैसेज दिखा सकती हैं या मर्ज करने की कोई अन्य कस्टम रणनीति अपना सकती हैं.

ऐसी अन्य स्थितियां भी होती हैं जहां आपको चाइल्ड सिमैंटिक को पैरंट सिमैंटिक में मर्ज करना होता है, लेकिन ऐसा नहीं होता. यहां दिए गए उदाहरण में, हमारे पास चाइल्ड एलिमेंट के साथ clickable सूची आइटम पैरंट है. हमें उम्मीद है कि पैरंट उन सभी को मर्ज कर देगा:

इमेज, कुछ टेक्स्ट, और बुकमार्क आइकॉन वाला सूची का आइटम
तीसरी इमेज. इमेज, कुछ टेक्स्ट, और बुकमार्क आइकॉन वाला सूची का आइटम.

@Composable
private fun ArticleListItem(
    openArticle: () -> Unit,
    addToBookmarks: () -> Unit,
) {

    Row(modifier = Modifier.clickable { openArticle() }) {
        // Merges with parent clickable:
        Icon(
            painter = painterResource(R.drawable.ic_logo),
            contentDescription = "Article thumbnail"
        )
        ArticleDetails()

        // Defies the merge due to its own clickable:
        BookmarkButton(onClick = addToBookmarks)
    }
}

जब उपयोगकर्ता clickable आइटम Row को दबाता है, तो लेख खुल जाता है. इसके अंदर, लेख को बुकमार्क करने के लिए एक BookmarkButton मौजूद है. यह नेस्ट किया गया बटन, अनमर्ज के तौर पर दिखता है. हालांकि, पंक्ति में मौजूद बाकी चाइल्ड कॉन्टेंट मर्ज किया गया है:

मर्ज किए गए ट्री में, पंक्ति नोड के अंदर मौजूद सूची में कई टेक्स्ट होते हैं. अनमर्ज किए गए ट्री में, हर टेक्स्ट कंपोज़ेबल के लिए अलग-अलग नोड होते हैं.
चौथी इमेज. मर्ज किए गए ट्री में, Row नोड के अंदर मौजूद सूची में कई टेक्स्ट होते हैं. अनमर्ज किए गए ट्री में, हर Text कंपोज़ेबल
के लिए अलग-अलग नोड होते हैं.

डिज़ाइन के हिसाब से, कुछ कंपोज़ेबल अपने-आप पैरंट के साथ मर्ज नहीं होते. पैरंट कॉम्पोनेंट अपने चाइल्ड कॉम्पोनेंट को मर्ज नहीं कर सकता, जब चाइल्ड कॉम्पोनेंट भी मर्ज हो रहे हों. ऐसा तब होता है, जब mergeDescendants = true सेटिंग को साफ़ तौर पर सेट किया गया हो या वे ऐसे कॉम्पोनेंट हों जो खुद को मर्ज करते हैं, जैसे कि बटन या क्लिक किए जा सकने वाले कॉम्पोनेंट. यह जानने से कि कुछ एपीआई कैसे मर्ज होते हैं या मर्ज होने से कैसे बचते हैं, आपको कुछ संभावित अनचाहे व्यवहारों को डीबग करने में मदद मिल सकती है.

मर्ज करने की सुविधा का इस्तेमाल तब करें, जब चाइल्ड एलिमेंट अपने पैरंट एलिमेंट के तहत एक लॉजिकल और सही ग्रुप बनाते हों. हालांकि, अगर नेस्ट किए गए चाइल्ड एलिमेंट के सिमैंटिक को मैन्युअल तरीके से अडजस्ट करने या हटाने की ज़रूरत है, तो अन्य एपीआई आपकी ज़रूरतों के हिसाब से ज़्यादा सही हो सकते हैं. उदाहरण के लिए, clearAndSetSemantics.

सिमैंटिक हटाएं और सेट करें

अगर सिमैंटिक जानकारी को पूरी तरह से मिटाना है या उसे ओवरराइट करना है, तो clearAndSetSemantics एक बेहतरीन एपीआई है.

जब किसी कॉम्पोनेंट को अपने और अपने डिसेंडेंट के सिमैंटिक को मिटाना हो, तो खाली लैम्ब्डा के साथ इस एपीआई का इस्तेमाल करें. जब इसके सिमैंटिक को ओवरराइट करना हो, तो लैम्ब्डा में अपना नया कॉन्टेंट शामिल करें.

ध्यान दें कि खाली लैम्ब्डा का इस्तेमाल करके, सिमैंटिक को मिटाने पर, मिटाए गए सिमैंटिक को इस जानकारी का इस्तेमाल करने वाले किसी भी उपभोक्ता को नहीं भेजा जाता. जैसे, सुलभता, जानकारी अपने-आप भरने की सुविधा या टेस्टिंग. clearAndSetSemantics{/*semantic information*/} की मदद से कॉन्टेंट को ओवरराइट करने पर, नए सिमैंटिक, एलिमेंट और उसके डिसेंडेंट के सभी पिछले सिमैंटिक को बदल देते हैं.

यहां कस्टम टॉगल कॉम्पोनेंट का एक उदाहरण दिया गया है. इसे इंटरैक्टिव लाइन के तौर पर दिखाया गया है, जिसमें एक आइकॉन और टेक्स्ट शामिल है:

// Developer might intend this to be a toggleable.
// Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied,
// a custom description is set, and a Role is applied.

@Composable
fun FavoriteToggle() {
    val checked = remember { mutableStateOf(true) }
    Row(
        modifier = Modifier
            .toggleable(
                value = checked.value,
                onValueChange = { checked.value = it }
            )
            .clearAndSetSemantics {
                stateDescription = if (checked.value) "Favorited" else "Not favorited"
                toggleableState = ToggleableState(checked.value)
                role = Role.Switch
            },
    ) {
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = null // not needed here

        )
        Text("Favorite?")
    }
}

आइकॉन और टेक्स्ट में कुछ सिमैंटिक जानकारी होती है. हालांकि, दोनों को साथ में देखने पर यह पता नहीं चलता कि इस कॉम्पोनेंट को टॉगल किया जा सकता है. मर्ज करना काफ़ी नहीं है, क्योंकि आपको कॉम्पोनेंट के बारे में ज़्यादा जानकारी देनी होगी.

ऊपर दिया गया स्निपेट, कस्टम टॉगल कॉम्पोनेंट बनाता है. इसलिए, आपको टॉगल करने की सुविधा के साथ-साथ stateDescription, toggleableState, और role सिमैंटिक जोड़ने होंगे. इस तरह, कॉम्पोनेंट की स्थिति और उससे जुड़ी कार्रवाई उपलब्ध होती है. उदाहरण के लिए, TalkBack "चालू करने के लिए दो बार टैप करें" के बजाय "टॉगल करने के लिए दो बार टैप करें" की सूचना देता है.

ओरिजनल सिमैंटिक को हटाकर, ज़्यादा जानकारी देने वाले नए सिमैंटिक सेट करने से, सुलभता सेवाएं अब यह देख सकती हैं कि यह टॉगल किया जा सकने वाला कॉम्पोनेंट है. इसकी स्थिति को बदला जा सकता है.

clearAndSetSemantics का इस्तेमाल करते समय, इन बातों का ध्यान रखें:

  • इस एपीआई के सेट होने पर, सेवाओं को कोई जानकारी नहीं मिलती. इसलिए, इसका इस्तेमाल कम से कम करना चाहिए.
    • एआई एजेंट और मिलती-जुलती सेवाएं, स्क्रीन को समझने के लिए सिमैंटिक जानकारी का इस्तेमाल कर सकती हैं. इसलिए, इसे सिर्फ़ ज़रूरत पड़ने पर ही मिटाया जाना चाहिए.
  • एपीआई लैम्ब्डा में कस्टम सिमैंटिक सेट किए जा सकते हैं.
  • मॉडिफ़ायर का क्रम मायने रखता है―यह एपीआई, लागू किए जाने के बाद के सभी सिमैंटिक को हटा देता है. भले ही, मर्ज करने की अन्य रणनीतियां कुछ भी हों.

सिमैंटिक छिपाएं

कुछ मामलों में, एलिमेंट को सुलभता सेवाओं को भेजने की ज़रूरत नहीं होती. ऐसा तब होता है, जब एलिमेंट की अतिरिक्त जानकारी सुलभता के लिए ज़रूरी न हो या वह सिर्फ़ विज़ुअल तौर पर सजावटी हो और इंटरैक्टिव न हो. ऐसे मामलों में, hideFromAccessibility एपीआई की मदद से एलिमेंट छिपाए जा सकते हैं.

यहां दिए गए उदाहरणों में ऐसे कॉम्पोनेंट शामिल हैं जिन्हें छिपाने की ज़रूरत पड़ सकती है: किसी कॉम्पोनेंट पर मौजूद ग़ैर-ज़रूरी वॉटरमार्क और जानकारी को सजाने के लिए इस्तेमाल किया गया वर्ण.

@Composable
fun WatermarkExample(
    watermarkText: String,
    content: @Composable () -> Unit,
) {
    Box {
        WatermarkedContent()
        // Mark the watermark as hidden to accessibility services.
        WatermarkText(
            text = watermarkText,
            color = Color.Gray.copy(alpha = 0.5f),
            modifier = Modifier
                .align(Alignment.BottomEnd)
                .semantics { hideFromAccessibility() }
        )
    }
}

@Composable
fun DecorativeExample() {
    Text(
        modifier =
        Modifier.semantics {
            hideFromAccessibility()
        },
        text = "A dot character that is used to decoratively separate information, like •"
    )
}

यहां hideFromAccessibility का इस्तेमाल करने से, यह पक्का होता है कि वॉटरमार्क और सजावट को सुलभता सेवाओं से छिपाया गया है. हालांकि, टेस्टिंग जैसे अन्य इस्तेमाल के उदाहरणों के लिए, उनके सिमैंटिक को अब भी बनाए रखा जाता है.

इस्तेमाल के उदाहरणों का ब्रेकडाउन

यहां इस्तेमाल के कुछ उदाहरण दिए गए हैं. इनसे यह समझने में मदद मिलेगी कि पिछले एपीआई के बीच साफ़ तौर पर अंतर कैसे किया जाए:

  • जब कॉन्टेंट को सुलभता सेवाओं के लिए इस्तेमाल न किया जाना हो:
    • hideFromAccessibility का इस्तेमाल तब करें, जब कॉन्टेंट शायद सजावटी या ग़ैर-ज़रूरी हो, लेकिन फिर भी उसकी जांच करना ज़रूरी हो.
    • जब सभी सेवाओं के लिए पैरंट और चिल्ड्रन सिमैंटिक को मिटाना हो, तब खाली लैम्ब्डा के साथ clearAndSetSemantics{} का इस्तेमाल करें.
    • जब किसी कॉम्पोनेंट के सिमैंटिक को मैन्युअल तरीके से सेट करना हो, तब लैम्ब्डा के अंदर मौजूद कॉन्टेंट के साथ clearAndSetSemantics{/*content*/} का इस्तेमाल करें.
  • जब कॉन्टेंट को एक इकाई के तौर पर माना जाना चाहिए और उसके सभी चाइल्ड एलिमेंट की जानकारी पूरी होनी चाहिए:
    • सिमैंटिक डिसेंडेंट को मर्ज करने की सुविधा का इस्तेमाल करें.
एपीआई के इस्तेमाल के अलग-अलग उदाहरणों वाली टेबल.
पांचवीं इमेज. एपीआई के इस्तेमाल के अलग-अलग उदाहरणों वाली टेबल.