Prinsip-prinsip untuk meningkatkan aksesibilitas aplikasi

Untuk membantu pengguna yang membutuhkan aksesibilitas, framework Android memungkinkan Anda membuat layanan aksesibilitas yang dapat menyajikan konten dari aplikasi kepada pengguna dan juga mengoperasikan aplikasi atas nama mereka.

Android menyediakan beberapa layanan aksesibilitas sistem, termasuk:

  • TalkBack: membantu orang-orang yang memiliki gangguan penglihatan atau tunanetra. Aplikasi ini mengumumkan konten melalui suara yang disintesis dan melakukan tindakan pada aplikasi sebagai respons atas gestur pengguna.
  • Tombol Akses: membantu orang-orang yang memiliki gangguan motorik. Fitur ini menandai elemen interaktif dan melakukan tindakan sebagai respons terhadap pengguna yang menekan tombol. Fitur ini memungkinkan pengontrolan perangkat hanya dengan satu atau dua tombol.

Untuk membantu pengguna yang membutuhkan fitur aksesibilitas agar dapat menggunakan aplikasi Anda, aplikasi Anda harus mengikuti praktik terbaik yang dijelaskan di halaman ini, yang disusun berdasarkan panduan sebagaimana tercantum dalam Menjadikan aplikasi lebih mudah diakses.

Setiap praktik terbaik ini, yang dijelaskan di bagian selanjutnya, dapat meningkatkan aksesibilitas aplikasi Anda lebih lanjut:

Elemen label
Pengguna harus dapat memahami konten dan tujuan setiap elemen UI yang interaktif dan bermanfaat dalam aplikasi Anda.
Menambahkan tindakan aksesibilitas
Dengan menambahkan tindakan aksesibilitas, Anda dapat memungkinkan pengguna layanan aksesibilitas menyelesaikan alur pengguna penting dalam aplikasi Anda.
Menggunakan fitur aksesibilitas bawaan
Compose menawarkan banyak perilaku aksesibilitas secara default. Manfaatkan perilaku aksesibilitas yang telah ditentukan sebelumnya untuk membuat komponen Anda dapat diakses dengan sedikit atau tanpa pekerjaan tambahan. Compose juga menyediakan cara untuk mendukung persyaratan aksesibilitas yang lebih spesifik yang tidak tercakup oleh fitur default.
Menggunakan isyarat selain warna
Pengguna harus dapat membedakan kategori elemen dalam UI dengan jelas. Untuk melakukannya, gunakan pola dan posisi serta warna untuk menunjukkan perbedaannya.
Menjadikan konten media lebih mudah diakses
Tambahkan deskripsi pada konten video atau audio aplikasi Anda, agar pengguna yang menikmati konten ini tidak perlu sepenuhnya mengandalkan isyarat visual atau aural.

Elemen label

Penting untuk menyediakan label yang deskriptif dan berguna kepada pengguna untuk setiap elemen UI interaktif di aplikasi Anda. Setiap label harus menjelaskan semantik elemen tertentu—yaitu, arti dan tujuan elemen. Pembaca layar seperti TalkBack dapat membacakan label ini kepada pengguna.

Dalam sebagian besar kasus, API Compose dan Material telah memiliki dukungan aksesibilitas default. Namun, jika Anda perlu menentukan properti semantik elemen UI secara manual, gunakan pengubah semantics dan properti contentDescription. Untuk mengetahui informasi selengkapnya tentang semantik, lihat Semantik.

Bagian berikut menjelaskan beberapa teknik pemberian label lainnya.

Elemen yang dapat diedit

Saat melabeli elemen yang dapat diedit, seperti kolom teks, sebaiknya tampilkan teks yang memberikan contoh input yang valid dalam elemen itu sendiri, selain menjadikan teks contoh ini tersedia bagi pembaca layar. Dalam situasi ini, Anda dapat menggunakan teks placeholder, yang juga disebut teks petunjuk.

Dalam contoh berikut, TextField memiliki parameter placeholder yang memberikan teks petunjuk.

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

Kolom teks juga biasanya memiliki label deskriptif yang sesuai dan menjelaskan apa yang harus dimasukkan pengguna sebagai input.

Dalam contoh berikut, TextField memiliki parameter label yang memberikan deskripsi aksesibilitas.

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

Untuk mengetahui informasi selengkapnya tentang teks dan input pengguna, lihat Mengonfigurasi kolom teks.

Elemen dalam koleksi

Saat menambahkan label ke elemen koleksi, setiap label harus unik. Dengan begitu, layanan aksesibilitas sistem dapat merujuk dengan tepat ke satu elemen di layar saat membacakan label. Hubungan ini memberi tahu pengguna kapan mereka menjelajahi UI atau kapan mereka memindahkan fokus ke elemen yang sudah mereka temukan.

Misalnya, jika Anda memiliki LazyColumn atau LazyRow, gunakan pengubah semantics untuk menetapkan collectionItemInfo unik ke setiap item, seperti yang ditunjukkan dalam cuplikan berikut:

MilkyWayList(
    modifier = Modifier
        .semantics {
            collectionInfo = CollectionInfo(
                rowCount = milkyWay.count(),
                columnCount = 1
            )
        }
) {
    milkyWay.forEachIndexed { index, text ->
        Text(
            text = text,
            modifier = Modifier.semantics {
                collectionItemInfo =
                    CollectionItemInfo(index, 0, 0, 0)
            }
        )
    }
}

Untuk mengetahui informasi selengkapnya tentang properti semantik untuk daftar dan petak, lihat Informasi daftar dan item.

Grup konten terkait

Jika aplikasi Anda menampilkan beberapa elemen UI yang membentuk grup secara otomatis, seperti detail lagu atau atribut pesan, atur elemen tersebut dalam penampung induk (seperti Column, Row, atau Box). Gunakan pengubah semantics penampung induk untuk menyetel mergeDescendants ke true.

Dengan demikian, layanan aksesibilitas dapat menyajikan deskripsi konten elemen dalam satu per satu, dalam satu pembacaan. Dengan menggabungkan elemen terkait, pengguna teknologi pendukung dapat menemukan informasi di layar dengan lebih efisien.

Dalam cuplikan berikut, composable Row bertindak sebagai penampung induk. Dalam Row terdapat elemen terkait yang menampilkan metadata untuk postingan blog—avatar penulis, nama penulis, dan perkiraan waktu membaca. Menetapkan mergeDescendants ke true mengelompokkan elemen dalam ini, sehingga layanan aksesibilitas dapat memperlakukannya sebagai satu unit.

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

Saat mengelompokkan elemen terkait seperti pada contoh sebelumnya, buat hanya penampung induk yang interaktif. Hindari menambahkan pengubah clickable atau focusable ke elemen turunan dalam. Sebagai gantinya, terapkan pengubah ke induk Row atau Column.

Karena layanan aksesibilitas membacakan deskripsi elemen inti dalam satu kalimat, penting untuk membuat setiap deskripsi sesingkat mungkin tetapi tetap menyampaikan maksud elemen tersebut.

Catatan: Secara umum, saat membuat deskripsi konten untuk grup, hindari menggabungkan teks anak grup. Tindakan ini membuat deskripsi grup menjadi tidak fleksibel, dan saat teks turunan berubah, deskripsi grup mungkin tidak lagi cocok dengan teks yang terlihat.

Dalam konteks daftar atau petak, pembaca layar dapat menggabungkan teks dari node teks turunan elemen daftar atau petak. Sebaiknya hindari mengubah pengumuman ini.

Untuk mengetahui informasi selengkapnya tentang menggabungkan semantik, lihat Menggabungkan dan menghapus.

Judul dalam teks

Beberapa aplikasi menggunakan judul untuk meringkas grup teks yang muncul di layar. Jika elemen tertentu merepresentasikan judul, Anda dapat menunjukkan tujuannya untuk layanan aksesibilitas dengan menyetel properti heading di pengubah semantics.

@Composable
private fun Subsection(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.headlineSmall,
        modifier = Modifier.semantics { heading() }
    )
}

Pengguna layanan aksesibilitas dapat memilih untuk memilih opsi navigasi antar-judul, bukan antar-paragraf atau antar-kata. Fleksibilitas ini akan meningkatkan pengalaman navigasi teks.

Untuk mengetahui informasi selengkapnya tentang properti semantik heading, lihat Judul.

Judul panel aksesibilitas

Di Android 9 (API level 28) dan yang lebih tinggi, Anda dapat memberikan judul yang mudah diakses untuk panel layar. Untuk tujuan aksesibilitas, panel adalah bagian jendela dengan tampilan visual yang mencolok.

Agar layanan aksesibilitas dapat memahami perilaku seperti jendela di panel, berikan judul yang deskriptif pada panel aplikasi Anda. Selanjutnya, layanan aksesibilitas dapat memberikan informasi yang lebih terperinci kepada pengguna saat tampilan atau konten panel berubah.

ShareSheet(
    message = "Choose how to share this photo",
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.TopCenter)
        .semantics { paneTitle = "New bottom sheet" }
)

Untuk mengetahui informasi selengkapnya tentang properti semantik paneTitle, lihat Komponen seperti jendela.

Elemen dekoratif

Jika elemen di UI Anda hanya ada untuk tujuan spacing visual atau tampilan visual, tetapkan properti yang sesuai pada elemen untuk menunjukkan bahwa layanan aksesibilitas dapat mengabaikannya.

Untuk composable Image atau Icon, tetapkan contentDescription = null. Untuk elemen dekoratif murni lainnya yang tidak memberikan konteks atau fungsionalitas, Anda dapat menggunakan hideFromAccessibility. Properti semantik ini memberi tahu layanan aksesibilitas untuk mengabaikan item.

Jika composable interaktif berisi elemen turunan dekoratif yang tidak interaktif, gunakan clearAndSetSemantics untuk memastikan bahwa layanan aksesibilitas tidak melintasinya. Perhatikan bahwa clearAndSetSemantics sepenuhnya menghapus semantik default elemen dan turunannya. Dengan demikian, Anda dapat menentukan elemen aksesibilitas baru yang terpadu. Biasanya, Anda menggunakan pendekatan ini untuk komponen kustom yang kompleks.

Dalam contoh berikut, Icon dan Text adalah elemen turunan dekoratif di dalam tombol kustom. Untuk mencegah layanan aksesibilitas melintasi setiap anak ini, Anda dapat menghapus semantiknya dengan menggunakan clearAndSetSemantics pada induk Row. Kode ini memberi tahu layanan aksesibilitas untuk memperlakukan seluruh Row sebagai tombol yang dapat dilalui:

// 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?")
    }
}

Untuk mengetahui informasi selengkapnya tentang menghapus semantik, lihat Menghapus dan menyetel semantik.

Menambahkan tindakan aksesibilitas

Penting untuk memastikan bahwa pengguna layanan aksesibilitas memiliki cara untuk menyelesaikan semua alur pengguna di aplikasi Anda.

Jika interaksi composable kustom Anda mengubah status aplikasi dengan cara yang tidak jelas, berikan label deskriptif untuk tindakan ketuk standar menggunakan parameter seperti onClickLabel atau onLongClickLabel di Modifier.clickable atau Modifier.combinedClickable.

Untuk interaksi kompleks yang tidak dapat dipetakan ke ketukan standar, gunakan customActions.

Misalnya, jika aplikasi Anda memungkinkan pengguna menarik item ke lokasi lain atau menggeser item dalam daftar, Anda dapat menyediakan cara alternatif untuk menyelesaikan alur pengguna ini dengan mengekspos tindakan ke layanan aksesibilitas. Dengan begitu, pengguna TalkBack, Voice Access, atau Tombol Akses dapat melakukan tindakan yang mungkin hanya tersedia melalui gestur.

Di Compose, Anda dapat menentukan tindakan aksesibilitas kustom melalui properti customActions di pengubah semantics, menggunakan CustomAccessibilityAction.

Misalnya, jika aplikasi Anda memungkinkan pengguna menggeser item untuk menutupnya, Anda dapat mengekspos fungsi melalui tindakan aksesibilitas kustom:

SwipeToDismissBox(
    modifier = Modifier.semantics {
        // Represents the swipe to dismiss for accessibility
        customActions = listOf(
            CustomAccessibilityAction(
                label = "Remove article from list",
                action = {
                    removeArticle()
                    true
                }
            )
        )
    },
    state = rememberSwipeToDismissBoxState(),
    backgroundContent = {}
) {
    ArticleListItem()
}

Dengan tindakan aksesibilitas kustom yang diterapkan, pengguna dapat mengakses tindakan melalui menu tindakan.

Untuk mengetahui informasi selengkapnya tentang tindakan kustom, lihat Tindakan kustom.

Membuat tindakan yang tersedia mudah dipahami

Jika elemen UI mendukung tindakan seperti sentuh lama, layanan aksesibilitas seperti TalkBack akan mengumumkannya sebagai "Ketuk dua kali dan tahan untuk menekan lama".

Pengumuman umum ini tidak memberikan konteks apa pun kepada pengguna tentang fungsi tindakan sentuh & tahan.

Agar pengumuman ini lebih bermanfaat, tentukan deskripsi yang bermakna untuk tindakan tersebut.

Di Compose, pengubah interaksi standar seperti clickable dan combinedClickable memiliki parameter bawaan (yaitu onClickLabel dan onLongClickLabel) yang dapat Anda gunakan untuk memberikan deskripsi tindakan, seperti dalam contoh berikut:

var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
    items(photos, { it.id }) { photo ->
        ImageItem(
            photo,
            Modifier
                .combinedClickable(
                    onClick = { activePhotoId = photo.id },
                    onLongClick = {
                        haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                        contextMenuPhotoId = photo.id
                    },
                    onLongClickLabel = stringResource(R.string.open_context_menu)
                )
        )
    }
}
if (contextMenuPhotoId != null) {
    PhotoActionsSheet(
        photo = photos.first { it.id == contextMenuPhotoId },
        onDismissSheet = { contextMenuPhotoId = null }
    )
}

Hal ini akan membuat TalkBack mengumumkan "Buka menu konteks", sehingga membantu pengguna memahami tujuan tindakan tersebut.

Anda juga dapat menentukan label secara langsung di pengubah semantics.

Untuk mengetahui informasi selengkapnya tentang cara merespons ketukan dan klik, lihat Ketuk dan tekan serta Elemen interaktif.

Menggunakan fitur aksesibilitas bawaan

Saat mendesain UI aplikasi, manfaatkan fitur aksesibilitas bawaan untuk menghindari penerapan ulang fungsi yang sudah ada. Material, Compose UI, dan Foundation API menerapkan dan menawarkan banyak praktik aksesibilitas secara default.

Di Jetpack Compose, gunakan composable bawaan seperti Button, Switch, dan Checkbox untuk membuat UI yang mudah diakses. Komponen ini sudah dikemas sebelumnya dengan pengubah semantics, seperti role dan stateDescription, yang dapat Anda gunakan untuk membuat aplikasi Anda lebih mudah diakses.

Menerapkan semantik ke komponen kustom

Saat membuat komponen kustom, perhatikan jenis dukungan aksesibilitas yang diperlukan komponen ini untuk memenuhi perannya. Sering kali, API Compose standar yang sudah Anda gunakan—seperti clickable, toggleable, atau selectable—sudah cukup karena API tersebut otomatis mengisi pohon semantik untuk Anda.

Namun, beberapa komponen memerlukan informasi yang lebih spesifik daripada yang disediakan oleh pengubah standar. Dalam kasus ini, cari pengubah khusus (seperti triStateToggleable) atau, jika tidak ada, berikan semantik secara eksplisit menggunakan Modifier.semantics tingkat rendah.

Misalnya, pertimbangkan TriStateSwitch, tombol dengan tiga status (Aktif, Nonaktif, dan Tidak Pasti).

Meskipun pengubah toggleable standar mengasumsikan dua status, pengubah triStateToggleable menangani kompleksitas status ketiga. Secara otomatis menetapkan aksesibilitas Role (Switch) dan State. Dengan cara ini, layanan aksesibilitas menerima informasi yang akurat, dan Anda tidak perlu menentukan semantik secara manual.

Cuplikan kode berikut menunjukkan TriStateSwitch menggunakan pendekatan ini:

@Composable
fun TriStateSwitch(
    state: ToggleableState,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    // A real implementation would include custom drawing for the switch.
    // This example uses a Box to demonstrate the semantics.
    Box(
        modifier = modifier
            .size(width = 64.dp, height = 40.dp)
            // triStateToggleable handles the semantics (Role and State)
            // automatically, so explicit Modifier.semantics is not needed here.
            .triStateToggleable(
                state = state,
                onClick = onClick,
                role = Role.Switch
            )
            // Add visual feedback based on the state
            .background(
                when (state) {
                    ToggleableState.On -> Color.Green
                    ToggleableState.Off -> Color.Gray
                    ToggleableState.Indeterminate -> Color.Yellow
                }
            )
    )
}

// Usage within another composable:
var state by remember { mutableStateOf(ToggleableState.Off) }
TriStateSwitch(
    state = state,
    onClick = {
        state = when (state) {
            ToggleableState.Off -> ToggleableState.Indeterminate
            ToggleableState.Indeterminate -> ToggleableState.On
            ToggleableState.On -> ToggleableState.Off
        }
    }
)

Saat membuat komponen kustom, pastikan Anda memberikan semua properti semantik yang relevan untuk tujuan aksesibilitas. Misalnya, jika komponen Anda meniru kontrol standar seperti tombol atau sakelar, properti ini mencakup peran komponen (seperti Role.Switch atau Role.Button), stateDescription (seperti "Aktif", "Nonaktif", "Dicentang", atau "Tidak dicentang"), dan label tindakan yang relevan. Untuk mengetahui informasi selengkapnya, lihat Komponen kustom.

Menggunakan petunjuk selain warna

Untuk membantu pengguna yang mengalami kekurangan daya penglihatan terhadap warna, gunakan petunjuk selain warna untuk membedakan elemen UI dalam layar aplikasi Anda. Teknik ini dapat mencakup penggunaan berbagai bentuk atau ukuran, penyediaan pola teks atau visual, atau penambahan info berbasis audio atau sentuhan (info via sentuhan) untuk menandai perbedaan elemen.

Gambar 1 menunjukkan dua versi aktivitas. Versi pertama hanya menggunakan warna untuk membedakan antara dua kemungkinan tindakan dalam alur kerja. Versi kedua menggunakan praktik terbaik yang menyertakan bentuk dan teks selain warna untuk menandai perbedaan antara kedua opsi tersebut:

Di sebelah kiri terdapat layar dengan dua tombol melingkar, satu berwarna hijau dan satu berwarna merah. Di sebelah kanan adalah layar yang sama, tetapi dua tombol melingkar diberi label dengan teks dan ikon yang bermakna.
Gambar 1. Contoh pembuatan elemen UI yang hanya menggunakan warna (kiri) dan yang menggunakan warna, bentuk, serta teks (kanan).

Menjadikan konten media lebih mudah diakses

Jika Anda mengembangkan aplikasi yang menyertakan konten media, seperti klip video atau rekaman audio, coba dukung pengguna dengan berbagai jenis aksesibilitas yang diperlukan untuk memahami materi ini. Secara khusus, coba lakukan hal berikut:

  • Sertakan kontrol yang memungkinkan pengguna menjeda atau menghentikan media, mengubah volume, dan mengaktifkan atau menonaktifkan subtitel (teks).
  • Jika video menyajikan informasi yang penting untuk menyelesaikan alur kerja, berikan konten yang sama dalam format alternatif, seperti transkrip.

Referensi lainnya

Untuk mengetahui informasi selengkapnya tentang cara menjadikan aplikasi Anda lebih mudah diakses, lihat referensi tambahan berikut:

Codelab

Melihat konten