ادغام و پاکسازی

از آنجایی که سرویس‌های دسترس‌پذیری در میان عناصر روی صفحه حرکت می‌کنند، مهم است که این عناصر گروه‌بندی، جدا شده و یا حتی در جزئیات درست پنهان شوند. هنگامی که تک تک اجزای سازنده سطح پایین در صفحه نمایش شما به طور مستقل برجسته می شوند، کاربران باید برای حرکت در سراسر صفحه تعامل زیادی داشته باشند. اگر عناصر به شدت با هم ادغام شوند، کاربران ممکن است متوجه نشوند که کدام عناصر به طور منطقی به هم تعلق دارند. اگر عناصری روی صفحه وجود داشته باشد که صرفاً تزئینی هستند، ممکن است از خدمات دسترسی پنهان شوند. در این موارد، می‌توانید از Compose API برای ادغام، پاک کردن و پنهان کردن معنایی استفاده کنید.

ادغام معناشناسی

هنگامی که یک اصلاح کننده clickable را روی یک والد قابل ترکیب اعمال می کنید، Compose به طور خودکار همه عناصر فرزند را در زیر آن ادغام می کند. برای درک اینکه چگونه مؤلفه‌های Compose Material و Foundation به طور پیش‌فرض از استراتژی‌های ادغام استفاده می‌کنند، بخش عناصر تعاملی را ببینید.

معمول است که یک کامپوننت از چندین ترکیب ترکیبی تشکیل شده باشد. این ترکیب‌پذیرها می‌توانند یک گروه منطقی را تشکیل دهند و هر کدام می‌توانند حاوی اطلاعات مهمی باشند، اما همچنان ممکن است بخواهید خدمات دسترسی به آن‌ها را به عنوان یک عنصر مشاهده کنید.

به عنوان مثال، به یک Composable فکر کنید که آواتار کاربر، نام او و برخی اطلاعات اضافی را نشان می دهد:

گروهی از عناصر UI شامل نام کاربر. نام انتخاب شده است.
شکل 1. گروهی از عناصر UI شامل نام کاربر. نام انتخاب شده است.

می توانید Compose را برای ادغام این عناصر با استفاده از پارامتر mergeDescendants در اصلاح کننده semantics فعال کنید. به این ترتیب، سرویس‌های دسترس‌پذیری مؤلفه را به‌عنوان یک موجودیت در نظر می‌گیرند و تمام ویژگی‌های معنایی فرزندان ادغام می‌شوند:

@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")
        }
    }
}

سرویس‌های دسترس‌پذیری اکنون روی کل کانتینر تمرکز می‌کنند و محتویات آن را ادغام می‌کنند:

گروهی از عناصر UI شامل نام کاربر. همه عناصر با هم انتخاب می شوند.
شکل 2. گروهی از عناصر UI شامل نام کاربر. همه عناصر با هم انتخاب می شوند.

هر ویژگی معنایی یک استراتژی ادغام تعریف شده دارد. به عنوان مثال، ویژگی ContentDescription تمام مقادیر ContentDescription را به یک لیست اضافه می کند. می توانید استراتژی ادغام یک ویژگی semantics را با بررسی اجرای mergePolicy آن در SemanticsProperties.kt بررسی کنید. ویژگی‌ها می‌توانند مقدار والد یا فرزند را بگیرند، مقادیر را در یک لیست یا رشته ادغام کنند، اصلاً اجازه ادغام را ندهند و به جای آن یک استثنا ایجاد کنند، یا هر استراتژی ادغام سفارشی دیگری.

سناریوهای دیگری وجود دارد که در آن شما انتظار دارید معناشناسی کودکان در یک سناریو والد ادغام شود، اما این اتفاق نمی افتد. در مثال زیر، ما یک آیتم لیست clickable را با عناصر فرزند داریم، و ممکن است انتظار داشته باشیم که والدین همه آنها را ادغام کند:

مورد فهرست با تصویر، مقداری متن و نماد نشانک
شکل 3. فهرست مورد با تصویر، مقداری متن و نماد نشانک.

@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 است. درخت ادغام نشده شامل گره های جداگانه برای هر متن قابل ترکیب است.
شکل 4. درخت ادغام شده حاوی چندین متن در یک لیست در داخل گره Row است. درخت ادغام نشده شامل گره های جداگانه برای هر Text قابل ترکیب است.

برخی از ترکیب‌پذیرها به‌طور خودکار تحت یک والد، با طراحی ادغام نمی‌شوند. هنگامی که فرزندان نیز در حال ادغام هستند، والدین نمی توانند فرزندان خود را ادغام کنند، چه از طریق تنظیم mergeDescendants = true به طور صریح یا با بودن اجزایی که خودشان ادغام می شوند، مانند دکمه ها یا قابل کلیک ها. دانستن اینکه چگونه API های خاص ادغام می شوند یا از ادغام سرپیچی می کنند، می تواند به شما در رفع اشکال برخی رفتارهای بالقوه غیرمنتظره کمک کند.

از ادغام زمانی استفاده کنید که عناصر کودک گروهی منطقی و معقول را زیر نظر والدین خود تشکیل می دهند. اما اگر کودکان تودرتو به تنظیم دستی یا حذف معنایی خود نیاز داشته باشند، API های دیگر ممکن است با نیازهای شما سازگارتر باشند (به عنوان مثال، clearAndSetSemantics ).

معناشناسی را پاک و تنظیم کنید

اگر اطلاعات معنایی باید به طور کامل پاک یا بازنویسی شود، یک API قدرتمند برای استفاده clearAndSetSemantics است.

هنگامی که یک مؤلفه نیاز به پاکسازی معنایی خود دارد، از این API با یک لامبدا خالی استفاده کنید. هنگامی که معنای آن باید بازنویسی شود، محتوای جدید خود را در لامبدا قرار دهید.

توجه داشته باشید که هنگام پاک کردن با یک لامبدا خالی، معنای پاک شده برای مصرف‌کننده‌ای که از این اطلاعات استفاده می‌کند، مانند دسترسی، تکمیل خودکار یا آزمایش، ارسال نمی‌شود. هنگام بازنویسی محتوا با 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?")
    }
}

اگرچه نماد و متن دارای برخی اطلاعات معنایی هستند، اما با هم نشان نمی‌دهند که این جزء قابل تغییر است. ادغام کافی نیست زیرا باید اطلاعات بیشتری در مورد مؤلفه ارائه دهید.

از آنجایی که قطعه بالا یک جزء تغییر سفارشی ایجاد می‌کند، باید قابلیت toggle و همچنین stateDescription ، toggleableState و معناشناسی role را اضافه کنید. به این ترتیب، وضعیت مؤلفه و عملکرد مربوطه در دسترس است - برای مثال، TalkBack به جای «دوبار ضربه برای فعال کردن»، «Double Tap to Toggle» را اعلام می‌کند.

با پاک کردن معنای اصلی و تنظیم موارد جدید و توصیفی تر، سرویس های دسترسی اکنون می توانند متوجه شوند که این یک جزء قابل تغییر است که می تواند حالت متناوب را تغییر دهد.

هنگام استفاده از clearAndSetSemantics ، موارد زیر را در نظر بگیرید:

  • از آنجایی که سرویس‌ها هنگام تنظیم این API هیچ اطلاعاتی دریافت نمی‌کنند، بهتر است از آن کم استفاده کنید.
    • اطلاعات معنایی به طور بالقوه می تواند توسط عوامل هوش مصنوعی و سرویس های مشابه برای درک صفحه استفاده شود و بنابراین فقط در صورت لزوم باید پاک شود.
  • معنای سفارشی ممکن است در API lambda تنظیم شود.
  • ترتیب اصلاح‌کننده‌ها مهم است - این API تمام معنایی را که بعد از آن اعمال می‌شود، بدون توجه به سایر استراتژی‌های ادغام پاک می‌کند.

معناشناسی را پنهان کنید

در برخی از سناریوها، عناصر نیازی به ارسال به سرویس‌های دسترس‌پذیری ندارند - شاید اطلاعات اضافی آن‌ها برای دسترس‌پذیری اضافی باشد یا صرفاً از نظر بصری تزئینی و غیر تعاملی باشد. در این موارد، می توانید عناصر را با hideFromAccessibility API پنهان کنید.

در مثال‌های زیر اجزایی وجود دارند که ممکن است نیاز به پنهان کردن داشته باشند: یک واترمارک اضافی که یک جزء را در بر می‌گیرد، و یک کاراکتر برای جدا کردن اطلاعات تزئینی استفاده می‌شود.

@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 در اینجا تضمین می‌کند که واترمارک و دکوراسیون از سرویس‌های دسترس‌پذیری پنهان هستند، اما همچنان معنای آنها را برای موارد استفاده دیگر، مانند آزمایش، حفظ می‌کند.

تفکیک موارد استفاده

در زیر خلاصه ای از موارد استفاده برای درک نحوه تمایز واضح بین API های قبلی آمده است:

  • وقتی قرار نیست محتوا توسط سرویس‌های دسترس‌پذیری استفاده شود:
    • هنگامی که محتوا احتمالاً تزئینی یا اضافی است، اما همچنان باید آزمایش شود، از hideFromAccessibility استفاده کنید.
    • از clearAndSetSemantics{} با لامبدا خالی استفاده کنید، زمانی که معنای والد و فرزند باید برای همه سرویس‌ها پاک شود.
    • هنگامی که معنای مولفه نیاز به تنظیم دستی دارد، از clearAndSetSemantics{/*content*/} با محتوای داخل لامبدا استفاده کنید.
  • زمانی که محتوا باید به عنوان یک موجود در نظر گرفته شود و برای کامل شدن همه اطلاعات مربوط به فرزندانش نیاز دارد:
    • از نوادگان معنایی ادغام استفاده کنید.
جدول با موارد استفاده متمایز از API.
شکل 5. جدول با موارد استفاده متمایز از API.
{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}