Konsep dan penerapan Jetpack Compose
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.
Elemen label
Penting untuk menyediakan label yang deskriptif dan berguna kepada pengguna di setiap elemen UI interaktif aplikasi Anda. Setiap label harus menjelaskan arti dan tujuan elemen tertentu. Pembaca layar seperti TalkBack dapat membacakan label ini kepada pengguna.
Umumnya, Anda menentukan deskripsi elemen UI dalam file resource
tata letak yang berisi elemen tersebut. Biasanya, Anda menambahkan label menggunakan
atribut contentDescription, seperti yang dijelaskan dalam panduan membuat aplikasi
lebih mudah diakses. Ada beberapa teknik pelabelan lain yang dijelaskan di bagian berikut.
Elemen yang dapat diedit
Saat melabeli elemen yang dapat diedit, seperti
objek EditText, 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 atribut android:hint, seperti ditunjukkan dalam cuplikan berikut:
<!-- The hint text for en-US locale would be "Apartment, suite, or building". --> <EditText android:id="@+id/addressLine2" android:hint="@string/aptSuiteBuilding" ... />
Dalam situasi ini, objek View harus memiliki atribut android:labelFor yang disetel ke ID elemen EditText. Untuk mengetahui detail selengkapnya, lihat bagian berikut.
Menyambungkan elemen yang salah satunya mendeskripsikan elemen lainnya
Elemen EditText biasanya memiliki objek View yang sesuai yang menjelaskan apa yang harus dimasukkan pengguna dalam elemen EditText. Anda dapat menunjukkan hubungan ini dengan menyetel
atribut android:labelFor objek View.
Contoh pelabelan untuk pasangan elemen tersebut ditunjukkan pada cuplikan berikut:
<!-- Label text for en-US locale would be "Username:" --> <TextView android:id="@+id/usernameLabel" ... android:text="@string/username" android:labelFor="@+id/usernameEntry" /> <EditText android:id="@+id/usernameEntry" ... /> <!-- Label text for en-US locale would be "Password:" --> <TextView android:id="@+id/passwordLabel" ... android:text="@string/password android:labelFor="@+id/passwordEntry" /> <EditText android:id="@+id/passwordEntry" android:inputType="textPassword" ... />
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.
Secara khusus, sertakan teks tambahan atau informasi kontekstual di
elemen dalam tata letak yang digunakan kembali—seperti
objek RecyclerView—sehingga setiap elemen turunan diidentifikasi secara unik.
Untuk melakukannya, setel deskripsi konten sebagai bagian dari implementasi adaptor Anda, seperti ditunjukkan dalam cuplikan kode berikut:
Kotlin
data class MovieRating(val title: String, val starRating: Integer) class MyMovieRatingsAdapter(private val myData: Array<MovieRating>): RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() { class MyRatingViewHolder(val ratingView: ImageView) : RecyclerView.ViewHolder(ratingView) override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) { val ratingData = myData[position] holder.ratingView.contentDescription = "Movie ${position}: " + "${ratingData.title}, ${ratingData.starRating} stars" } }
Java
public class MovieRating { private String title; private int starRating; // ... public String getTitle() { return title; } public int getStarRating() { return starRating; } } public class MyMovieRatingsAdapter extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> { private MovieRating[] myData; public static class MyRatingViewHolder extends RecyclerView.ViewHolder { public ImageView ratingView; public MyRatingViewHolder(ImageView iv) { super(iv); ratingView = iv; } } @Override public void onBindViewHolder(MyRatingViewHolder holder, int position) { MovieRating ratingData = myData[position]; holder.ratingView.setContentDescription("Movie " + position + ": " + ratingData.getTitle() + ", " + ratingData.getStarRating() + " stars") } }
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, yang umumnya merupakan subclass ViewGroup. Setel atribut
android:screenReaderFocusable
objek container
ke true, dan setiap atribut
android:focusable
objek inti ke false. Dengan demikian, layanan aksesibilitas dapat menyajikan deskripsi konten elemen
inti, satu per satu, dalam satu pembacaan.
Dengan menggabungkan elemen terkait ini, pengguna teknologi pendukung dapat
menemukan informasi di layar dengan lebih efisien.
Cuplikan berikut berisi bagian konten yang terkait satu sama lain, sehingga elemen penampung, instance ConstraintLayout, memiliki atribut android:screenReaderFocusable yang disetel ke true dan setiap elemen TextView inti memiliki atribut android:focusable yang disetel ke false:
<!-- In response to a single user interaction, accessibility services announce both the title and the artist of the song. --> <ConstraintLayout android:id="@+id/song_data_container" ... android:screenReaderFocusable="true"> <TextView android:id="@+id/song_title" ... android:focusable="false" android:text="@string/my_song_title" /> <TextView android:id="@+id/song_artist" android:focusable="false" android:text="@string/my_songwriter" /> </ConstraintLayout>
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, Anda harus menghindari pembuatan deskripsi konten untuk grup dengan menggabungkan teks elemen turunannya. 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.
Grup bertingkat
Jika antarmuka aplikasi Anda menyajikan informasi multidimensi, seperti
daftar acara festival harian, gunakan atribut android:screenReaderFocusable
pada penampung dalam grup. Skema pelabelan ini memberikan keseimbangan yang baik antara jumlah pembacaan yang diperlukan untuk menemukan konten layar dan durasi setiap pembacaan.
Cuplikan kode berikut menunjukkan satu metode untuk memberi label pada grup di dalam grup yang lebih besar:
<!-- In response to a single user interaction, accessibility services announce the events for a single stage only. --> <ConstraintLayout android:id="@+id/festival_event_table" ... > <ConstraintLayout android:id="@+id/stage_a_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage A. --> </ConstraintLayout> <ConstraintLayout android:id="@+id/stage_b_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage B. --> </ConstraintLayout> </ConstraintLayout>
Judul dalam teks
Beberapa aplikasi menggunakan judul untuk meringkas grup teks yang muncul di layar. Jika
elemen View tertentu merepresentasikan judul, Anda dapat menunjukkan tujuan judul tersebut
untuk layanan aksesibilitas dengan menyetel atribut
android:accessibilityHeading elemen ke
true.
Pengguna layanan aksesibilitas dapat memilih untuk memilih opsi navigasi antar-judul, bukan antar-paragraf atau antar-kata. Fleksibilitas ini akan meningkatkan pengalaman navigasi teks.
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, seperti konten suatu fragmen. 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.
Untuk menentukan judul panel, gunakan
atribut android:accessibilityPaneTitle,
seperti ditampilkan dalam cuplikan berikut:
<!-- Accessibility services receive announcements about content changes that are scoped to either the "shopping cart view" section (top) or "browse items" section (bottom) --> <MyShoppingCartView android:id="@+id/shoppingCartContainer" android:accessibilityPaneTitle="@string/shoppingCart" ... /> <MyShoppingBrowseView android:id="@+id/browseItemsContainer" android:accessibilityPaneTitle="@string/browseProducts" ... />
Elemen dekoratif
Jika elemen di UI Anda hanya ada untuk spacing visual atau tujuan tampilan
visual, setel
atribut android:importantForAccessibility
ke "no".
Menambahkan tindakan aksesibilitas
Penting untuk mengizinkan pengguna layanan aksesibilitas melakukan semua alur pengguna dengan mudah dalam aplikasi Anda. Misalnya, jika pengguna dapat menggeser item dalam daftar, tindakan ini juga dapat diekspos ke layanan aksesibilitas sehingga pengguna memiliki cara alternatif untuk menyelesaikan alur pengguna yang sama.
Membuat semua tindakan dapat diakses
Pengguna TalkBack, Voice Access, atau Switch Access mungkin memerlukan cara alternatif untuk menyelesaikan alur pengguna tertentu dalam aplikasi. Untuk tindakan yang terkait dengan gestur seperti tarik lalu lepas atau geser, aplikasi Anda dapat mengekspos tindakan dengan cara yang dapat diakses oleh pengguna layanan aksesibilitas.
Dengan menggunakan tindakan aksesibilitas, aplikasi dapat memberikan cara alternatif bagi pengguna untuk menyelesaikan tindakan.
Misalnya, jika aplikasi Anda memungkinkan pengguna menggeser item, Anda juga dapat mengekspos fungsi melalui tindakan aksesibilitas kustom, seperti ini:
Kotlin
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive) ) { _, _ -> // Same method executed when swiping on itemView archiveItem() true }
Java
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive), (view, arguments) -> { // Same method executed when swiping on itemView archiveItem(); return true; } );
With the custom accessibility action implemented, users can access the action through the actions menu.
Make available actions understandable
When a view supports actions such as touch & hold, an accessibility service such as TalkBack announces it as "Double tap and hold to long press."
This generic announcement doesn't give the user any context about what a touch & hold action does.
To make this announcement more descriptive, you can replace the accessibility action’s announcement like so:
Kotlin
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null )
Java
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null );
This results in TalkBack announcing "Double tap and hold to favorite," helping users understand the purpose of the action.
Extend system widgets
Note: When you design your app's UI, use or extend
system-provided widgets that are as far down Android's class hierarchy as
possible. System-provided widgets that are far down the hierarchy already
have most of the accessibility capabilities your app needs. It's easier
to extend these system-provided widgets than to create your own from the more
generic View,
ViewCompat,
Canvas, and
CanvasCompat
classes.
If you must extend View or Canvas directly, which
might be necessary for a highly customized experience or a game level, see
Make custom views more
accessible.
This section uses the example of implementing a special type of
Switch called TriSwitch while following
best practices around extending system widgets. A TriSwitch
object works similarly to a Switch object, except that each instance of
TriSwitch allows the user to toggle among three possible states.
Extend from far down the class hierarchy
The Switch object inherits from several framework UI classes in its hierarchy:
View ↳ TextView ↳ Button ↳ CompoundButton ↳ Switch
Sebaiknya class TriSwitch yang baru diperluas secara langsung dari class
Switch. Dengan demikian, framework aksesibilitas Android
menyediakan sebagian besar kemampuan aksesibilitas yang diperlukan class TriSwitch:
- Tindakan aksesibilitas: informasi untuk sistem tentang cara layanan aksesibilitas
dapat mengemulasi setiap kemungkinan input pengguna yang dilakukan pada objek
TriSwitch. (Diwarisi dariView.) - Peristiwa aksesibilitas: informasi untuk layanan aksesibilitas tentang setiap
kemungkinan cara agar tampilan objek
TriSwitchdapat berubah saat layar dimuat ulang atau diperbarui. (Diwarisi dariView.) - Karakteristik: detail setiap objek
TriSwitch, seperti konten teks yang ditampilkannya. (Diwarisi dariTextView.) - Informasi status: deskripsi tentang status objek
TriSwitchsaat ini, misalnya "dicentang" atau "tidak dicentang". (Diwarisi dariCompoundButton.) - Deskripsi teks tentang status: penjelasan berbasis teks tentang apa yang direpresentasikan oleh
setiap status. (Diwarisi dari
Switch.)
Perilaku dari Switch dan superclass-nya ini hampir sama dengan
perilaku objek TriSwitch. Oleh karena itu, implementasi Anda dapat
berfokus pada perluasan jumlah kemungkinan status dari dua menjadi tiga.
Menentukan peristiwa kustom
Saat Anda memperluas widget sistem, Anda mungkin mengubah aspek tentang cara pengguna berinteraksi dengan widget tersebut. Penting untuk menentukan perubahan interaksi ini agar layanan aksesibilitas dapat memperbarui widget aplikasi Anda seolah-olah pengguna berinteraksi dengan widget secara langsung.
Pedoman umumnya adalah, untuk setiap callback berbasis tampilan yang Anda ganti,
Anda juga perlu menentukan ulang tindakan aksesibilitas yang sesuai dengan mengganti
ViewCompat.replaceAccessibilityAction().
Dalam pengujian aplikasi, Anda dapat memvalidasi perilaku tindakan yang dtentukan ulang tersebut dengan
memanggil
ViewCompat.performAccessibilityAction().
Cara kerja prinsip ini untuk objek TriSwitch
Tidak seperti objek Switch biasa, mengetuk siklus objek TriSwitch akan mengalami siklus lewat
tiga kemungkinan status. Oleh karena itu, tindakan
aksesibilitas ACTION_CLICK yang terkait perlu diperbarui:
Kotlin
class TriSwitch(context: Context) : Switch(context) { // 0, 1, or 2 var currentState: Int = 0 private set init { updateAccessibilityActions() } private fun updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label) { view, args -> moveToNextState() }) } private fun moveToNextState() { currentState = (currentState + 1) % 3 } }
Java
public class TriSwitch extends Switch { // 0, 1, or 2 private int currentState; public int getCurrentState() { return currentState; } public TriSwitch() { updateAccessibilityActions(); } private void updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label, (view, args) -> moveToNextState()); } private void moveToNextState() { currentState = (currentState + 1) % 3; } }
Referensi lainnya
Untuk mempelajari lebih lanjut cara menjadikan aplikasi lebih mudah diakses, lihat referensi tambahan berikut: