پیش فرض های API

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

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

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

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

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

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

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

یک کادر انتخاب با padding پیش‌فرض با عرض و ارتفاع ۴۸ dp.
شکل ۱. یک کادر انتخاب با حاشیه پیش‌فرض.

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

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

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

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

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

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

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

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

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

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

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

@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 عمدتاً برای استفاده در عناصر گرافیکی مانند تصاویر در نظر گرفته شده است. کامپوننت‌های متریال، مانند Button یا Text ، و رفتارهای عملی، مانند clickable یا toggleable ، با معانی از پیش تعریف شده دیگری همراه هستند که رفتار ذاتی آنها را توصیف می‌کنند و می‌توانند از طریق سایر APIهای Compose تغییر داده شوند.

عناصر تعاملی

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

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

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

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

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 و تنظیم برچسب click در آنجا، تنظیم 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
                }
            )
        }
    )
}

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

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

اجزای سفارشی

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

همچنین می‌توانید نمونه‌ای از یک کامپوننت toggle سفارشی را در بخش Clear and set semantics و همچنین اطلاعات دقیق‌تری در مورد نحوه پشتیبانی از دسترسی در کامپوننت‌های سفارشی را در دستورالعمل‌های API بیابید.

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}