پیش‌فرض‌های میانای برنامه‌سازی کاربردی

«طراحی مواد»، «واسط کاربر Compose»، و «میاناهای برنامه‌سازی کاربردی Foundation» به‌طور پیش‌فرض بسیاری از رویه‌های دسترس‌پذیر را پیاده‌سازی و ارائه می‌کنند. آن‌ها حاوی معناشناسی داخلی هستند که از نقش و عملکرد خاص خود پیروی می‌کنند. این یعنی اکثر پشتیبانی‌های دسترس‌پذیری با کار اضافی کم یا بدون کار اضافی ارائه می‌شود.

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

درک معناشناسی و الگوهای دسترس‌پذیری پیش‌فرض در واسط‌های برنامه‌نویسی کاربردی Compose به شما کمک می‌کند از آن‌ها با درنظر گرفتن دسترس‌پذیری استفاده کنید. این کار همچنین به شما کمک می‌کند در عناصر سفارشی بیشتری از دسترس‌پذیری پشتیبانی کنید.

حداقل اندازه هدف‌های لمسی

هر عنصر روی صفحه که فردی بتواند روی آن کلیک کند، آن را لمس کند، یا با آن تعامل داشته باشد باید به‌اندازه کافی بزرگ باشد تا تعامل قابل‌اعتمادی داشته باشد. هنگام تعیین اندازه این عناصر، حتماً حداقل اندازه را روی ۴۸ پیکسل مستقل از تراکم تنظیم کنید تا به‌درستی از دستورالعمل‌های دسترس‌پذیری «طراحی مواد» پیروی کنید.

عناصر Material—مانند Checkbox، RadioButton، Switch، Slider، و Surface—این اندازه حداقلی را به‌صورت داخلی تنظیم می‌کنند، اما فقط زمانی که عنصر بتواند کنش‌های کاربر را دریافت کند. برای مثال، وقتی Checkbox دارای پارامتر onCheckedChange است که روی مقدار غیرتهی تنظیم شده است، چارگوش انتخاب دارای حاشیه می‌شود تا عرض و ارتفاع آن حداقل ۴۸ dp باشد.

@Composable
private fun CheckableCheckbox() {
    Checkbox(checked = true, onCheckedChange = {})
}

چارگوش انتخابی با بالشتک پیش‌فرض با عرض و ارتفاع ۴۸ dp.
شکل ۱. چارگوش انتخابی با لایه‌گذاری پیش‌فرض.

وقتی پارامتر onCheckedChange روی null تنظیم می‌شود، حاشیه اضافه نمی‌شود، زیرا نمی‌توان مستقیماً با عنصر تعامل داشت.

@Composable
private fun NonClickableCheckbox() {
    Checkbox(checked = true, onCheckedChange = null)
}

چارگوش انتخابی که حاشیه‌ای ندارد.
شکل ۲. چارگوش انتخابی بدون حاشیه.

هنگام پیاده‌سازی کنترل‌های انتخاب مثل Switch، RadioButton، یا Checkbox، معمولاً رفتار کلیک‌کردنی را با تنظیم کردن بازخوان کلیک روی عنصر ترکیبی به null و افزودن toggleable یا اصلاح‌گر selectable به عنصر ترکیبی والد به ظرف والد منتقل می‌کنید.

@Composable
private fun CheckableRow() {
    MaterialTheme {
        var checked by remember { mutableStateOf(false) }
        Row(
            Modifier
                .toggleable(
                    value = checked,
                    role = Role.Checkbox,
                    onValueChange = { checked = !checked }
                )
                .padding(16.dp)
                .fillMaxWidth()
        ) {
            Text("Option", Modifier.weight(1f))
            Checkbox(checked = checked, onCheckedChange = null)
        }
    }
}

چارگوش انتخابی در کنار نوشتار «گزینه» که انتخاب و لغو انتخاب می‌شود.
شکل ۳. چارگوش انتخابی با عملکرد کلیک‌کردنی.

وقتی اندازه یک عنصر ترکیبی کلیک‌کردنی کوچک‌تر از حداقل اندازه هدف لمسی باشد، Compose همچنان اندازه هدف لمسی را افزایش می‌دهد. این کار را با بزرگ کردن اندازه هدف لمس در خارج از مرزهای عنصر ترکیبی انجام می‌دهد.

مثال زیر حاوی Box بسیار کوچکی است که قابل‌کلیک است. منطقه هدف لمس به‌طور خودکار فراتر از مرزهای Box گسترش می‌یابد، بنابراین تک‌ضرب زدن در کنار Box همچنان رویداد کلیک را راه‌اندازی می‌کند.

@Composable
private fun SmallBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .size(1.dp)
        )
    }
}

چارگوش کلیک‌کردنی بسیار کوچکی که با ضربه زدن در کنار چارگوش به هدف لمسی بزرگ‌تری گسترش می‌یابد.
شکل ۴. یک چارگوش کلیک‌کردنی بسیار کوچک که به هدف لمسی بزرگ‌تری گسترش می‌یابد.

برای جلوگیری از هم‌پوشانی احتمالی بین نواحی لمسی عناصر ترکیبی مختلف، همیشه از اندازه حداقلی به‌اندازه کافی بزرگ برای عنصر ترکیبی استفاده کنید. در این مثال، این یعنی از اصلاح‌گر sizeIn برای تنظیم حداقل اندازه برای چارگوش داخلی استفاده کنید:

@Composable
private fun LargeBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .sizeIn(minWidth = 48.dp, minHeight = 48.dp)
        )
    }
}

اندازه چارگوش بسیار کوچک مثال قبلی افزایش می‌یابد تا هدف لمسی بزرگ‌تری ایجاد شود.
شکل ۵. هدف لمسی جعبه بزرگ‌تر.

عناصر گرافیکی

وقتی یک عنصر ترکیبی Image یا Icon تعریف می‌کنید، هیچ روش خودکاری برای چارچوب Android وجود ندارد تا بفهمد برنامه چه چیزی را نمایش می‌دهد. باید شرح نوشتاری عنصر گرافیکی را ارائه دهید.

صفحه‌ای را تصور کنید که کاربر بتواند صفحه فعلی را با دوستانش هم‌رسانی کند. این صفحه حاوی نماد هم‌رسانی کلیک‌کردنی است:

نوار چهار نماد کلیک‌کردنی، با نماد «هم‌رسانی» برجسته شده است.
شکل ۶. ردیفی از نمادهای کلیک‌کردنی با نماد «هم‌رسانی» انتخاب‌شده.

چارچوب Android نمی‌تواند براساس نماد به‌تنهایی آن را برای کاربر کم‌بینا توصیف کند. چارچوب Android به شرح نوشتاری اضافه‌ای برای نماد نیاز دارد.

پارامتر contentDescription عنصر گرافیکی را توصیف می‌کند. از رشته بومی‌سازی‌شده استفاده کنید، زیرا برای کاربر قابل‌مشاهده است.

@Composable
private fun ShareButton(onClick: () -> Unit) {
    IconButton(onClick = onClick) {
        Icon(
            imageVector = Icons.Filled.Share,
            contentDescription = stringResource(R.string.label_share)
        )
    }
}

برخی‌از عناصر گرافیکی صرفاً تزئینی هستند و ممکن است نخواهید آن‌ها را به کاربر منتقل کنید. وقتی پارامتر contentDescription را روی null تنظیم می‌کنید، به چارچوب Android نشان می‌دهید که این عنصر کنش‌ها یا وضعیت مرتبط ندارد.

@Composable
private fun PostImage(post: Post, modifier: Modifier = Modifier) {
    val image = post.imageThumb ?: painterResource(R.drawable.placeholder_1_1)

    Image(
        painter = image,
        // Specify that this image has no semantic meaning
        contentDescription = null,
        modifier = modifier
            .size(40.dp, 40.dp)
            .clip(MaterialTheme.shapes.small)
    )
}

contentDescription عمدتاً برای استفاده در عناصر گرافیکی درنظر گرفته شده است، مثل تصاویر. عناصر Material، مانند Button یا Text، و رفتارهای کنش‌پذیر، مانند clickable یا toggleable، با معناشناسی‌های ازپیش تعریف‌شده دیگری همراه هستند که رفتار ذاتی آن‌ها را توصیف می‌کنند و می‌توانند ازطریق دیگر «میاناهای برنامه‌سازی کاربردی Compose» تغییر کنند.

عناصر تعاملی

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

برای مثال، Button «عنصر» ممکن است از نماد کودک و مقداری نوشتار تشکیل شده باشد. به‌جای اینکه با کودکان به‌عنوان افراد جداگانه رفتار شود، Material Button به‌طور پیش‌فرض معناشناسی فرزندانش را ادغام می‌کند، بنابراین خدمات دسترس‌پذیری می‌تواند آن‌ها را براساس آن گروه‌بندی کند:

دکمه‌هایی با معناشناسی فرزندان ادغام‌نشده دربرابر ادغام‌شده.
شکل ۷. دکمه‌هایی با معناشناسی فرزندان ادغام‌نشده دربرابر ادغام‌شده.

به‌همین ترتیب، استفاده از اصلاح‌گر clickable نیز باعث می‌شود یک عنصر ترکیبی معناشناسی فرزندانش را در یک نهاد واحد ادغام کند، که با نمایش کنش مربوطه به خدمات دسترس‌پذیری ارسال می‌شود:

Row(
    // Uses `mergeDescendants = true` under the hood
    modifier = Modifier.clickable { openArticle() }
) {
    Icon(
        painter = painterResource(R.drawable.ic_logo),
        contentDescription = "Open",
    )
    Text("Accessibility in Compose")
}

همچنین می‌توانید onClickLabel خاصی را در عنصر کلیک‌کردنی والد تنظیم کنید تا اطلاعات تکمیلی به خدمات دسترس‌پذیری ارائه دهد و نمایش صیقلی‌تری از کنش ارائه دهد:

Row(
    modifier = Modifier
        .clickable(onClickLabel = "Open this article") {
            openArticle()
        }
) {
    Icon(
        painter = painterResource(R.drawable.ic_logo),
        contentDescription = "Open"
    )
    Text("Accessibility in Compose")
}

بااستفاده از TalkBack به‌عنوان مثال، این اصلاح‌گر clickable و برچسب کلیک آن به TalkBack امکان می‌دهد راهنمایی کنشی «برای باز کردن این مقاله، دوضربه بزنید» را ارائه دهد، به‌جای بازخورد پیش‌فرض عمومی‌تر «برای فعال کردن، دوضربه بزنید».

این بازخورد بسته به نوع کنش تغییر می‌کند. فشار طولانی راهنمایی TalkBack «برای» را ارائه می‌دهد، و پس‌از آن برچسبی می‌آید:

Row(
    modifier = Modifier
        .combinedClickable(
            onLongClickLabel = "Bookmark this article",
            onLongClick = { addToBookmarks() },
            onClickLabel = "Open this article",
            onClick = { openArticle() },
        )
) {}

در برخی موارد، ممکن است دسترسی مستقیم به اصلاح‌کننده clickable نداشته باشید (برای مثال، وقتی در لایه تودرتوی پایین‌تری تنظیم شده باشد)، اما همچنان بخواهید برچسب اعلان را از مقدار پیش‌فرض تغییر دهید. برای انجام این کار، بااستفاده از اصلاح‌کننده semantics و تنظیم برچسب کلیک در آنجا، تنظیم clickable را از اصلاح اعلان جدا کنید تا نمایش کنش را اصلاح کنید:

@Composable
private fun ArticleList(openArticle: () -> Unit) {
    NestedArticleListItem(
        // Clickable is set separately, in a nested layer:
        onClickAction = openArticle,
        // Semantics are set here:
        modifier = Modifier.semantics {
            onClick(
                label = "Open this article",
                action = {
                    // Not needed here: openArticle()
                    true
                }
            )
        }
    )
}

لازم نیست کنش کلیک را دوبار ارسال کنید. «میاناهای برنامه‌سازی کاربردی» موجود «نوشتن»، مثل clickable یا Button، این کار را برایتان انجام می‌دهند. منطق ادغام تأیید می‌کند که برچسب و کنش اصلاح‌گر بیرونی‌ترین برای اطلاعات موجود انجام می‌شود. در مثال قبلی، NestedArticleListItem به‌طور خودکار کنش کلیک openArticle() را به معناشناسی clickable خود منتقل می‌کند. می‌توانید کنش کلیک را در کنش اصلاح‌گر معنایی دوم تهی بگذارید. اما، برچسب کلیک از اصلاح‌کننده معنایی دوم onClick(label = "Open this document") گرفته می‌شود زیرا در اصلاح‌کننده اول وجود نداشت.

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

عناصر سفارشی

هنگام ساختن عنصر سفارشی، پیاده‌سازی عنصر مشابه در کتابخانه Material یا دیگر کتابخانه‌های Compose را بررسی کنید. سپس، رفتار دسترس‌پذیری آن را درصورت لزوم تقلید یا اصلاح کنید. برای مثال، اگر «Material» Checkbox را با پیاده‌سازی خودتان جایگزین کنید، نگاه کردن به پیاده‌سازی Checkbox موجود به شما یادآوری می‌کند که اصلاح‌گر triStateToggleable را اضافه کنید، که ویژگی‌های دسترس‌پذیری مؤلفه را مدیریت می‌کند. علاوه‌براین، از اصلاح‌کننده‌های Foundation به‌طور گسترده استفاده کنید، زیرا این اصلاح‌کننده‌ها شامل ملاحظات دسترس‌پذیری داخلی و رویه‌های Compose موجود است که در این بخش پوشش داده شده است.

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