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

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

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

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

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

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

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

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

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

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

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

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

اگر عنصر باید اندازه قابل‌مشاهده کوچک‌تری داشته باشد، به‌جای آن از اصلاح‌کننده minimumInteractiveComponentSize از Material 3 استفاده کنید. این ویژگی حداقل ۴۸ dp از فضای چیدمان را در هر بُعد رزرو می‌کند و عنصر را در مرکز آن فضا قرار می‌دهد، بنابراین عنصر اندازه ترسیم‌شده خود را حفظ می‌کند و عناصر اطراف آن برای ایجاد فضا جابه‌جا می‌شوند. اصلاح‌کننده هدف لمس را به‌تنهایی گسترش نمی‌دهد: بلکه فضایی را در چیدمان برای گسترش شرح‌داده‌شده در بالا باقی می‌گذارد. مؤلفه‌های Material مانند Checkbox از این اصلاح‌کننده به‌صورت داخلی استفاده می‌کنند. آن را قبل‌از هرگونه اصلاح‌کننده اندازه قرار دهید، زیرا اصلاح‌کننده اندازه قبل‌از آن، فضایی را که می‌تواند رزرو کند محدود می‌کند.

@Composable
private fun MinimumInteractiveBox() {
    var clicked by remember { mutableStateOf(false) }
    Row(verticalAlignment = Alignment.CenterVertically) {
        Box(
            Modifier
                .clickable { clicked = !clicked }
                .minimumInteractiveComponentSize()
                .size(24.dp)
                .background(if (clicked) Color.DarkGray else Color.Black)
        )
        Text("Option")
    }
}

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

وقتی 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 API تغییر کنند.

عناصر تعاملی

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

برای مثال، یک Button Material ممکن است شامل یک نماد فرزند و مقداری نوشتار باشد. به‌جای اینکه با فرزندان به‌عنوان فرد رفتار شود، Material 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 نداشته باشید (برای مثال، وقتی در جایی در لایه تودرتوی پایین‌تر تنظیم شده باشد)، اما همچنان بخواهید برچسب اعلام را از حالت پیش‌فرض تغییر دهید. برای انجام این کار، تنظیم clickable را از اصلاح کردن اعلان بااستفاده از اصلاح‌کننده semantics و تنظیم برچسب کلیک در آنجا جدا کنید تا نمایش کنش را اصلاح کنید:

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

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

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

اجزای سفارشی

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

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