Google berkomitmen untuk mendorong terwujudnya keadilan rasial bagi komunitas Kulit Hitam. Lihat caranya.

Menjadikan tampilan kustom lebih mudah diakses

Jika aplikasi Anda memerlukan komponen tampilan kustom, Anda harus melakukan beberapa tugas tambahan untuk membuat tampilan tersebut lebih mudah diakses. Berikut adalah tugas utama untuk meningkatkan aksesibilitas tampilan kustom Anda:

Menangani klik pengontrol arah

Pada sebagian besar perangkat, mengklik tampilan menggunakan pengontrol arah akan mengirimkan KeyEvent dengan KEYCODE_DPAD_CENTER ke tampilan yang saat ini menjadi fokus. Semua tampilan Android standar sudah menangani KEYCODE_DPAD_CENTER dengan tepat. Saat membuat kontrol View kustom, pastikan peristiwa ini memiliki efek yang sama dengan menyentuh tampilan di layar sentuh.

Kontrol kustom Anda juga harus memperlakukan peristiwa KEYCODE_ENTER sama seperti KEYCODE_DPAD_CENTER. Pendekatan ini menjadikan interaksi dari keyboard lengkap jauh lebih mudah bagi pengguna.

Mengimplementasikan metode API aksesibilitas

Peristiwa aksesibilitas adalah pesan tentang interaksi pengguna dengan komponen antarmuka visual dalam aplikasi Anda. Pesan ini ditangani oleh Layanan Aksesibilitas, yang menggunakan informasi dalam peristiwa ini untuk menghasilkan masukan dan perintah tambahan. Di Android 4.0 (API Level 14) dan yang lebih tinggi, metode untuk menghasilkan peristiwa aksesibilitas telah diperluas untuk memberikan informasi yang lebih mendetail daripada antarmuka AccessibilityEventSource yang diperkenalkan di Android 1.6 (API Level 4). Metode aksesibilitas yang diperluas adalah bagian dari class View serta class View.AccessibilityDelegate. Metode tersebut adalah sebagai berikut:

sendAccessibilityEvent()
(API Level 4) Metode ini dipanggil saat pengguna mengambil tindakan pada suatu tampilan. Peristiwa tersebut diklasifikasikan dengan jenis tindakan pengguna seperti TYPE_VIEW_CLICKED. Anda biasanya tidak perlu mengimplementasikan metode ini kecuali untuk membuat tampilan kustom.
sendAccessibilityEventUnchecked()
(API Level 4) Metode ini digunakan saat kode panggilan perlu secara langsung mengontrol pemeriksaan aksesibilitas yang diaktifkan pada perangkat (AccessibilityManager.isEnabled()). Jika mengimplementasikan metode ini, Anda harus melakukan panggilan seolah-olah aksesibilitas sedang diaktifkan, terlepas dari setelan sistem yang sebenarnya. Anda biasanya tidak perlu mengimplementasikan metode ini untuk tampilan kustom.
dispatchPopulateAccessibilityEvent()
(API Level 4) Sistem akan memanggil metode ini saat tampilan kustom Anda menghasilkan peristiwa aksesibilitas. Mulai API Level 14, implementasi default metode ini akan memanggil onPopulateAccessibilityEvent() untuk tampilan ini dan metode dispatchPopulateAccessibilityEvent() untuk setiap turunan tampilan ini. Agar dapat mendukung layanan aksesibilitas pada revisi Android sebelum 4.0 (API Level 14), Anda harus mengganti metode ini dan mengisi getText() dengan teks deskriptif untuk tampilan kustom Anda, yang diucapkan oleh layanan aksesibilitas, misalnya TalkBack.
onPopulateAccessibilityEvent()
(API Level 14) Metode ini akan menyetel perintah teks AccessibilityEvent yang diucapkan untuk tampilan Anda. Metode ini juga dipanggil jika tampilan tersebut adalah turunan tampilan yang menghasilkan peristiwa aksesibilitas.

Catatan: Mengubah atribut tambahan di luar teks dalam metode ini berpotensi menimpa properti yang disetel oleh metode lain. Meskipun dapat mengubah atribut peristiwa aksesibilitas dengan metode ini, Anda harus membatasi perubahan tersebut pada konten teks, dan menggunakan metode onInitializeAccessibilityEvent() untuk mengubah properti lain dari peristiwa tersebut.

Catatan: Jika implementasi peristiwa ini sepenuhnya mengganti teks output tanpa mengizinkan bagian lain tata letak Anda untuk mengubah kontennya, jangan memanggil implementasi super metode ini dalam kode Anda.

onInitializeAccessibilityEvent()
(API Level 14) Sistem akan memanggil metode ini untuk mendapatkan informasi tambahan tentang status tampilan, di luar konten teks. Jika tampilan kustom memberikan kontrol interaktif di luar TextView atau Button yang sederhana, Anda harus mengganti metode ini dan menetapkan informasi tambahan tentang tampilan Anda ke peristiwa menggunakan metode ini, seperti jenis kolom sandi, jenis kotak centang, atau status yang memberikan interaksi atau masukan kepada pengguna. Jika mengganti metode ini, Anda harus memanggil implementasi supernya, lalu hanya mengubah properti yang belum disetel oleh class super.
onInitializeAccessibilityNodeInfo()
(API Level 14) Metode ini akan memberikan layanan aksesibilitas dengan informasi tentang status tampilan. Implementasi View default memiliki kumpulan standar properti tampilan. Namun, jika tampilan kustom Anda memberikan kontrol interaktif di luar TextView atau Button yang sederhana, Anda harus mengganti metode ini dan menetapkan informasi tambahan tentang tampilan Anda ke objek AccessibilityNodeInfo yang ditangani oleh metode ini.
onRequestSendAccessibilityEvent()
(API Level 14) Sistem akan memanggil metode ini saat turunan tampilan Anda telah menghasilkan AccessibilityEvent. Langkah ini memungkinkan tampilan induk untuk mengubah peristiwa aksesibilitas dengan informasi tambahan. Anda harus mengimplementasikan metode ini hanya jika tampilan kustom Anda dapat memiliki tampilan turunan dan jika tampilan induk dapat memberikan informasi konteks ke peristiwa aksesibilitas yang akan berguna untuk layanan aksesibilitas.

Untuk mendukung metode aksesibilitas ini bagi tampilan kustom, Anda harus melakukan salah satu pendekatan berikut:

  • Jika aplikasi Anda menargetkan Android 4.0 (API level 14) dan yang lebih tinggi, ganti dan implementasikan metode aksesibilitas yang tercantum di atas secara langsung dalam class tampilan kustom Anda.
  • Jika tampilan kustom Anda dimaksudkan agar kompatibel dengan Android 1.6 (API Level 4) dan yang lebih tinggi, tambahkan Android Support Library, revisi 5 atau yang lebih baru, ke project Anda. Kemudian, dalam class tampilan kustom Anda, panggil metode ViewCompat.setAccessibilityDelegate() untuk mengimplementasikan metode aksesibilitas di atas. Untuk contoh pendekatan ini, lihat AccessibilityDelegateSupportActivity contoh Android Support Library (revisi 5 atau yang lebih baru) di (<sdk>/extras/android/support/v4/samples/Support4Demos/)

Dalam kedua kasus tersebut, Anda harus mengimplementasikan metode aksesibilitas berikut untuk class tampilan kustom Anda:

Untuk informasi selengkapnya tentang pengimplementasian metode tersebut, lihat Mengisi Peristiwa Aksesibilitas.

Mengirim peristiwa aksesibilitas

Tergantung pada spesifikasi tampilan kustom, Anda mungkin perlu mengirim objek AccessibilityEvent pada waktu yang berbeda atau untuk peristiwa yang tidak ditangani oleh implementasi default. Class View akan memberikan implementasi default untuk jenis peristiwa berikut:

Catatan: Peristiwa pengarahan mouse (hover) dikaitkan dengan fitur Klik untuk Info yang menggunakan peristiwa tersebut sebagai pemicu dalam memberikan perintah suara untuk elemen antarmuka pengguna.

Secara umum, Anda harus mengirim AccessibilityEvent kapan pun konten tampilan kustom Anda berubah. Misalnya, jika Anda mengimplementasikan panel penggeser kustom yang memungkinkan pengguna memilih nilai numerik dengan menekan panah kiri atau kanan, tampilan kustom Anda akan menampilkan peristiwa berjenis TYPE_VIEW_TEXT_CHANGED kapan pun nilai penggeser tersebut berubah. Kode contoh berikut ini akan menunjukkan penggunaan metode sendAccessibilityEvent() untuk melaporkan peristiwa ini.

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
    return when(keyCode) {
        KeyEvent.KEYCODE_DPAD_LEFT -> {
            currentValue--
            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED)
            true
        }
        ...
    }
}

Java

@Override
public boolean onKeyUp (int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
        currentValue--;
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
        return true;
    }
    ...
}

Mengisi peristiwa aksesibilitas

Setiap AccessibilityEvent memiliki kumpulan properti yang diperlukan yang menggambarkan status tampilan saat ini. Properti tersebut mencakup hal-hal seperti nama class, deskripsi konten, dan status yang dicentang dari suatu tampilan. Properti khusus yang diperlukan untuk setiap jenis peristiwa dijelaskan dalam dokumentasi referensi AccessibilityEvent. Implementasi View akan memberikan nilai default untuk properti tersebut. Banyak dari nilai tersebut, termasuk nama class dan stempel waktu peristiwa, disediakan secara otomatis. Jika Anda membuat komponen tampilan kustom, Anda harus memberikan beberapa informasi tentang konten dan karakteristik tampilan. Informasi tersebut dapat dibuat sederhana seperti label tombol, tetapi juga dapat menyertakan informasi status tambahan yang ingin Anda tambahkan ke peristiwa.

Persyaratan minimum untuk memberikan informasi ke layanan aksesibilitas dengan tampilan kustom adalah pengimplementasian dispatchPopulateAccessibilityEvent(). Metode ini dipanggil oleh sistem guna meminta informasi untuk AccessibilityEvent dan menjadikan tampilan kustom Anda kompatibel dengan layanan aksesibilitas pada Android 1.6 (API Level 4) dan yang lebih tinggi. Kode contoh berikut ini akan menunjukkan implementasi dasar metode ini.

Kotlin

override fun dispatchPopulateAccessibilityEvent(event: AccessibilityEvent): Boolean {
    // Call the super implementation to populate its text to the event, which
    // calls onPopulateAccessibilityEvent() on API Level 14 and up.
    return super.dispatchPopulateAccessibilityEvent(event).let { completed ->

        // In case this is running on a API revision earlier that 14, check
        // the text content of the event and add an appropriate text
        // description for this custom view:
        if (text?.isNotEmpty() == true) {
            event.text.add(text)
            true
        } else {
            completed
        }
    }
}

Java

@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
    // Call the super implementation to populate its text to the event, which
    // calls onPopulateAccessibilityEvent() on API Level 14 and up.
    boolean completed = super.dispatchPopulateAccessibilityEvent(event);

    // In case this is running on a API revision earlier that 14, check
    // the text content of the event and add an appropriate text
    // description for this custom view:
    CharSequence text = getText();
    if (!TextUtils.isEmpty(text)) {
        event.getText().add(text);
        return true;
    }
    return completed;
}

Untuk Android 4.0 (API Level 14) dan yang lebih tinggi, gunakan metode onPopulateAccessibilityEvent() dan onInitializeAccessibilityEvent() untuk mengisi atau mengubah informasi dalam AccessibilityEvent. Gunakan metode onPopulateAccessibilityEvent() secara khusus untuk menambahkan atau mengubah konten teks peristiwa, yang diubah menjadi perintah suara oleh layanan aksesibilitas seperti TalkBack. Gunakan metode onInitializeAccessibilityEvent() untuk mengisi informasi tambahan tentang peristiwa, seperti status pemilihan tampilan.

Selain itu, implementasikan metode onInitializeAccessibilityNodeInfo(). Objek AccessibilityNodeInfo yang diisi oleh metode ini akan digunakan oleh layanan aksesibilitas untuk menyelidiki hierarki tampilan yang menghasilkan peristiwa aksesibilitas setelah menerima peristiwa tersebut, untuk memperoleh informasi konteks yang lebih mendetail dan memberikan masukan yang sesuai kepada pengguna.

Kode contoh di bawah ini menunjukkan cara mengganti ketiga metode tersebut menggunakan ViewCompat.setAccessibilityDelegate(). Perlu diperhatikan bahwa kode contoh ini mengharuskan Android Support Library untuk API Level 4 (revisi 5 atau yang lebih baru) ditambahkan ke project Anda.

Kotlin

ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {

    override fun onPopulateAccessibilityEvent(host: View, event: AccessibilityEvent) {
        super.onPopulateAccessibilityEvent(host, event)
        // We call the super implementation to populate its text for the
        // event. Then we add our text not present in a super class.
        // Very often you only need to add the text for the custom view.
        if (text?.isNotEmpty() == true) {
            event.text.add(text)
        }
    }

    override fun onInitializeAccessibilityEvent(host: View, event: AccessibilityEvent) {
        super.onInitializeAccessibilityEvent(host, event);
        // We call the super implementation to let super classes
        // set appropriate event properties. Then we add the new property
        // (checked) which is not supported by a super class.
        event.isChecked = isChecked()
    }

    override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
        super.onInitializeAccessibilityNodeInfo(host, info)
        // We call the super implementation to let super classes set
        // appropriate info properties. Then we add our properties
        // (checkable and checked) which are not supported by a super class.
        info.isCheckable = true
        info.isChecked = isChecked()
        // Quite often you only need to add the text for the custom view.
        if (text?.isNotEmpty() == true) {
            info.text = text
        }
    }
})

Java

ViewCompat.setAccessibilityDelegate(new AccessibilityDelegateCompat() {
    @Override
    public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
        super.onPopulateAccessibilityEvent(host, event);
        // We call the super implementation to populate its text for the
        // event. Then we add our text not present in a super class.
        // Very often you only need to add the text for the custom view.
        CharSequence text = getText();
        if (!TextUtils.isEmpty(text)) {
            event.getText().add(text);
        }
    }
    @Override
    public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(host, event);
        // We call the super implementation to let super classes
        // set appropriate event properties. Then we add the new property
        // (checked) which is not supported by a super class.
        event.setChecked(isChecked());
    }
    @Override
    public void onInitializeAccessibilityNodeInfo(View host,
            AccessibilityNodeInfoCompat info) {
        super.onInitializeAccessibilityNodeInfo(host, info);
        // We call the super implementation to let super classes set
        // appropriate info properties. Then we add our properties
        // (checkable and checked) which are not supported by a super class.
        info.setCheckable(true);
        info.setChecked(isChecked());
        // Quite often you only need to add the text for the custom view.
        CharSequence text = getText();
        if (!TextUtils.isEmpty(text)) {
            info.setText(text);
        }
    }
}

Anda dapat mengimplementasikan metode ini secara langsung dalam class tampilan kustom. Untuk contoh lain pendekatan ini, lihat AccessibilityDelegateSupportActivity contoh Android Support Library (revisi 5 atau yang lebih baru) di (<sdk>/extras/android/support/v4/samples/Support4Demos/).

Memberikan konteks aksesibilitas yang disesuaikan

Di Android 4.0 (API Level 14), framework telah disempurnakan untuk memungkinkan layanan aksesibilitas memeriksa hierarki tampilan komponen antarmuka pengguna yang memuatnya, yang menghasilkan peristiwa aksesibilitas. Penyempurnaan ini memungkinkan layanan aksesibilitas memberikan kumpulan informasi kontekstual yang jauh lebih kaya untuk membantu pengguna.

Ada beberapa kasus ketika layanan aksesibilitas tidak bisa mendapatkan informasi yang memadai dari hierarki tampilan. Contoh hal ini adalah kontrol antarmuka kustom yang memiliki dua atau beberapa area yang dapat diklik secara terpisah, seperti kontrol kalender. Dalam kasus ini, layanan tersebut tidak dapat memperoleh informasi yang memadai karena sub-bagian yang dapat diklik bukan bagian dari hierarki tampilan.

Gambar 1. Tampilan kalender kustom dengan elemen hari yang dapat dipilih.

Dalam contoh yang ditampilkan pada Gambar 1, seluruh kalender diimplementasikan sebagai satu tampilan. Dengan demikian, jika Anda tidak melakukan hal lainnya, layanan aksesibilitas tidak akan menerima cukup informasi tentang konten tampilan dan pilihan pengguna dalam tampilan. Misalnya, jika pengguna mengklik pada hari yang berisi 17, framework aksesibilitas hanya akan menerima informasi deskripsi untuk seluruh kontrol kalender. Dalam hal ini, layanan aksesibilitas TalkBack hanya akan mengumumkan "Kalender" atau, jika sedikit lebih baik, "Kalender bulan April" dan pengguna akan bertanya-tanya hari apa yang dipilih.

Untuk memberikan informasi konteks yang memadai bagi layanan aksesibilitas dalam situasi seperti ini, framework memberikan cara guna menentukan hierarki tampilan virtual. Hierarki tampilan virtual adalah cara bagi developer aplikasi untuk memberikan hierarki tampilan tambahan ke layanan aksesibilitas yang lebih cocok dengan informasi aktual di layar. Pendekatan ini memungkinkan layanan aksesibilitas memberikan informasi konteks yang lebih bermanfaat bagi pengguna.

Situasi lain ketika hierarki tampilan virtual mungkin diperlukan adalah antarmuka pengguna yang berisi kumpulan kontrol (tampilan) yang memiliki beberapa fungsi yang terkait erat. Di sana, tindakan pada satu kontrol akan memengaruhi konten dari satu atau beberapa elemen, seperti pemilih angka dengan tombol atas dan bawah yang terpisah. Dalam hal ini, layanan aksesibilitas tidak dapat memperoleh informasi yang memadai karena tindakan pada satu kontrol mengubah konten di kontrol lain dan hubungan antara kontrol tersebut mungkin tidak terlihat oleh layanan. Untuk menangani situasi ini, kelompokkan kontrol terkait dengan tampilan yang memuatnya dan berikan hierarki tampilan virtual dari container ini untuk menggambarkan dengan jelas informasi dan perilaku yang diberikan oleh kontrol tersebut.

Agar dapat memberikan hierarki tampilan virtual untuk suatu tampilan, ganti metode getAccessibilityNodeProvider() dalam tampilan kustom Anda atau kelompok tampilan dan tampilkan implementasi AccessibilityNodeProvider. Untuk implementasi contoh fitur aksesibilitas ini, lihat AccessibilityNodeProviderActivity dalam project contoh ApiDemos. Anda dapat mengimplementasikan hierarki tampilan virtual yang kompatibel dengan Android 1.6 dan yang lebih tinggi menggunakan Support Library dengan metode ViewCompat.getAccessibilityNodeProvider() dan memberikan implementasi dengan AccessibilityNodeProviderCompat.

Menangani peristiwa sentuh kustom

Kontrol tampilan kustom mungkin memerlukan perilaku peristiwa sentuh non-standar. Misalnya, kontrol kustom mungkin menggunakan metode pemroses onTouchEvent(MotionEvent) untuk mendeteksi peristiwa ACTION_DOWN serta ACTION_UP dan memicu peristiwa klik khusus. Untuk menjaga kompatibilitas dengan layanan aksesibilitas, kode yang menangani peristiwa klik kustom ini harus melakukan hal berikut:

  1. Menghasilkan AccessibilityEvent yang sesuai untuk tindakan klik yang diinterpretasikan.
  2. Mengaktifkan layanan aksesibilitas untuk menjalankan tindakan klik kustom bagi pengguna yang tidak dapat menggunakan layar sentuh.

Untuk menangani persyaratan ini dengan cara yang efisien, kode Anda harus mengganti metode performClick(), yang harus memanggil implementasi super metode ini, lalu menjalankan tindakan apa pun yang diperlukan oleh peristiwa klik. Saat tindakan klik kustom terdeteksi, kode tersebut kemudian akan memanggil metode performClick() Anda. Contoh kode berikut ini menunjukkan pola tersebut.

Kotlin

class CustomTouchView(context: Context) : View(context) {

    var downTouch = false

    override fun onTouchEvent(event: MotionEvent): Boolean {
        super.onTouchEvent(event)

        // Listening for the down and up touch events
        return when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                downTouch = true
                true
            }

            MotionEvent.ACTION_UP -> if (downTouch) {
                downTouch = false
                performClick() // Call this method to handle the response, and
                // thereby enable accessibility services to
                // perform this action for a user who cannot
                // click the touchscreen.
                true
            } else {
                false
            }

            else -> false  // Return false for other touch events
        }
    }

    override fun performClick(): Boolean {
        // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any
        super.performClick()

        // Handle the action for the custom click here

        return true
    }
}

Java

class CustomTouchView extends View {

    public CustomTouchView(Context context) {
        super(context);
    }

    boolean downTouch = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

        // Listening for the down and up touch events
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downTouch = true;
                return true;

            case MotionEvent.ACTION_UP:
                if (downTouch) {
                    downTouch = false;
                    performClick(); // Call this method to handle the response, and
                                    // thereby enable accessibility services to
                                    // perform this action for a user who cannot
                                    // click the touchscreen.
                    return true;
                }
        }
        return false; // Return false for other touch events
    }

    @Override
    public boolean performClick() {
        // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any
        super.performClick();

        // Handle the action for the custom click here

        return true;
    }
}

Pola yang ditampilkan di atas akan memastikan bahwa peristiwa klik kustom kompatibel dengan layanan aksesibilitas menggunakan metode performClick() untuk menghasilkan peristiwa aksesibilitas dan memberikan titik masuk bagi layanan aksesibilitas untuk bertindak atas nama pengguna dalam menjalankan peristiwa klik kustom ini.

Catatan: Jika tampilan kustom Anda memiliki area berbeda yang dapat diklik, seperti tampilan kalender kustom, Anda harus mengimplementasikan hierarki tampilan virtual dengan mengganti getAccessibilityNodeProvider() dalam tampilan kustom agar kompatibel dengan layanan aksesibilitas.