درحال ادغام و پاک‌سازی

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

ادغام معنایی

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

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

برای مثال، یک composable را درنظر بگیرید که چهرک کاربر، نام او، و برخی اطلاعات اضافی را نشان می‌دهد:

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

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

@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 فرزند را به فهرست اضافه می‌کند. می‌توانید استراتژی ادغام ویژگی معنایی را با بررسی پیاده‌سازی mergePolicy آن در SemanticsProperties.kt بررسی کنید. مشخصات می‌توانند مقدار والد یا فرزند را بگیرند، مقادیر را در یک فهرست یا رشته ادغام کنند، اصلاً اجازه ادغام ندهند و به‌جای آن استثنا ایجاد کنند، یا هر استراتژی ادغام سفارشی دیگری را اتخاذ کنند.

سناریوهای دیگری وجود دارد که در آن‌ها انتظار دارید معناشناسی فرزند در معناشناسی والد ادغام شود، اما این اتفاق نمی‌افتد. در مثال زیر، 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 برای نشانک‌گذاری مقاله وجود دارد. این دکمه تودرتو به‌صورت ادغام‌نشده نشان داده می‌شود، درحالی‌که بقیه محتوای فرزند داخل ردیف ادغام شده است:

درخت ادغام‌شده حاوی چندین نوشتار در فهرستی داخل گره «ردیف» است. درخت ادغام‌نشده حاوی گره‌های جداگانه برای هر Text composable است.
شکل ۴. درخت ادغام‌شده حاوی چندین نوشتار در فهرستی داخل گره 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، موارد زیر را درنظر بگیرید:

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

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

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

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