Özel görünümleri daha erişilebilir yapın

Uygulamanız bir özel görünüm bileşeni gerektiriyorsa görünümü daha erişilebilir hale getirmeniz gerekir. Aşağıdaki adımlar, bu sayfada açıklandığı gibi özel görünümünüzün erişilebilirliğini iyileştirebilir:

  • Yön kumandası tıklamalarını yönetme.
  • Accessibility API yöntemlerini uygulayın.
  • Özel görünümünüze özgü AccessibilityEvent nesneleri gönderin.
  • Görünümünüz için AccessibilityEvent ve AccessibilityNodeInfo alanlarını doldurun.

Yön kumandası tıklamalarını yönetme

Çoğu cihazda, yön kumandası kullanarak bir görünümü tıkladığınızda o anda odaklanılan görünüme KEYCODE_DPAD_CENTER simgesiyle KeyEvent gönderilir. Tüm standart Android görünümleri KEYCODE_DPAD_CENTER işlemini doğru bir şekilde ele alır. Özel View kontrol oluştururken, bu etkinliğin dokunmatik ekrandaki görünüme dokunmakla aynı etkiye sahip olduğundan emin olun.

Özel denetiminiz, KEYCODE_ENTER etkinliğini KEYCODE_DPAD_CENTER ile aynı şekilde işlemelidir. Bu, tam bir klavyeyle etkileşimleri kullanıcılar için kolaylaştırır.

Accessibility API yöntemlerini uygulama

Erişilebilirlik etkinlikleri, kullanıcıların uygulamanızın görsel arayüz bileşenleriyle etkileşimleri hakkındaki mesajlardır. Bu mesajlar, erişilebilirlik hizmetleri tarafından işlenir. Bu hizmetler, bu etkinliklerdeki bilgileri ek geri bildirim ve istem oluşturmak için kullanır. Erişilebilirlik yöntemleri View ve View.AccessibilityDelegate sınıflarının bir parçasıdır. Yöntemler aşağıdaki gibidir:

dispatchPopulateAccessibilityEvent()
Özel görünümünüz bir erişilebilirlik etkinliği oluşturduğunda sistem bu yöntemi çağırır. Bu yöntemin varsayılan uygulaması, bu görünüm için onPopulateAccessibilityEvent() yöntemini ve ardından bu görünümün her bir alt öğesi için dispatchPopulateAccessibilityEvent() yöntemini çağırır.
onInitializeAccessibilityEvent()
Sistem bu yöntemi, görünümün metin içeriği dışındaki durumu hakkında ek bilgi edinmek için çağırır. Özel görünümünüz, basit bir TextView veya Button dışında etkileşimli kontrol sağlıyorsa bu yöntemi kullanarak görünümünüzle ilgili ek bilgileri (şifre alanı türü, onay kutusu türü veya etkinliğe kullanıcı etkileşimi ya da geri bildirim sağlayan durumlar gibi) ayarlayın. Bu yöntemi geçersiz kılarsanız süper uygulamasını çağırın ve yalnızca süper sınıf tarafından ayarlanmayan özellikleri değiştirin.
onInitializeAccessibilityNodeInfo()
Bu yöntem, erişilebilirlik hizmetlerine görünümün durumu hakkında bilgi sağlar. Varsayılan View uygulamasının standart bir görünüm özellikleri grubu vardır. Ancak özel görünümünüz, basit bir TextView veya Button dışında etkileşimli kontrol sağlıyorsa bu yöntemi geçersiz kılıp görünümünüzle ilgili ek bilgileri bu yöntemle işlenen AccessibilityNodeInfo nesnesine ayarlayın.
onPopulateAccessibilityEvent()
Bu yöntem, AccessibilityEvent içindeki sesli metin istemini görünümünüz için ayarlar. Görünüm, erişilebilirlik etkinliği oluşturan bir görünümün alt öğesiyse de bu şekilde adlandırılır.
onRequestSendAccessibilityEvent()
Görünümünüzün alt öğesi AccessibilityEvent oluşturduğunda sistem bu yöntemi çağırır. Bu adım, üst görünümün ek bilgilerle erişilebilirlik etkinliğini değiştirmesini sağlar. Bu yöntemi yalnızca özel görünümünüz alt görünümlere sahip olduğunda ve üst görünüm, erişilebilirlik hizmetleri için yararlı olan erişilebilirlik etkinliği hakkında bağlam bilgisi sağlayabiliyorsa uygulayın.
sendAccessibilityEvent()
Kullanıcı, bir görüntüleme üzerinde işlem yaptığında sistem bu yöntemi çağırır. Etkinlik, TYPE_VIEW_CLICKED gibi bir kullanıcı işlemi türüyle sınıflandırılır. Genel olarak, özel görünümünüzün içeriği her değiştiğinde bir AccessibilityEvent göndermeniz gerekir.
sendAccessibilityEventUnchecked()
Bu yöntem, çağrı kodunun cihazda (AccessibilityManager.isEnabled()) etkinleştirilen erişilebilirlik kontrolünü doğrudan kontrol etmesi gerektiğinde kullanılır. Bu yöntemi uygularsanız sistem ayarından bağımsız olarak çağrıyı erişilebilirlik etkinmiş gibi gerçekleştirin. Genellikle bu yöntemi özel bir görünüm için uygulamanız gerekmez.

Erişilebilirliği desteklemek için önceki erişilebilirlik yöntemlerini doğrudan özel görünüm sınıfınızda geçersiz kılın ve uygulayın.

Özel görünüm sınıfınız için en azından aşağıdaki erişilebilirlik yöntemlerini uygulayın:

  • dispatchPopulateAccessibilityEvent()
  • onInitializeAccessibilityEvent()
  • onInitializeAccessibilityNodeInfo()
  • onPopulateAccessibilityEvent()

Bu yöntemlerin uygulanması hakkında daha fazla bilgi için erişilebilirlik etkinliklerini doldurma hakkındaki bölüme bakın.

Erişilebilirlik etkinliklerini gönder

Özel görünümünüzün özelliklerine bağlı olarak, AccessibilityEvent nesnelerini farklı zamanlarda veya varsayılan uygulama tarafından işlenmeyen etkinlikler için göndermesi gerekebilir. View sınıfı, şu etkinlik türleri için varsayılan bir uygulama sunar:

Genel olarak, özel görünümünüzün içeriği her değiştiğinde bir AccessibilityEvent göndermeniz gerekir. Örneğin, kullanıcının sol veya sağ ok tuşuna basarak sayısal bir değer seçmesine olanak tanıyan özel bir kaydırma çubuğu uyguluyorsanız özel görünümünüz, kaydırma çubuğu değeri her değiştiğinde TYPE_VIEW_TEXT_CHANGED etkinliği yayınlamalıdır. Aşağıdaki kod örneğinde, bu etkinliği bildirmek için sendAccessibilityEvent() yönteminin kullanımı gösterilmektedir.

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;
    }
    ...
}

Erişilebilirlik etkinliklerini doldur

Her AccessibilityEvent, görünümün mevcut durumunu açıklayan bir dizi gerekli özelliğe sahiptir. Bu özellikler; görünümün sınıf adı, içerik açıklaması ve işaretlendi durumu gibi bilgileri içerir. Her bir etkinlik türü için gereken belirli özellikler AccessibilityEvent referans belgelerinde açıklanmıştır.

View uygulaması, bu gerekli özellikler için varsayılan değerler sağlar. Sınıf adı ve etkinlik zaman damgası dahil bu değerlerin çoğu otomatik olarak sağlanır. Özel bir görünüm bileşeni oluşturuyorsanız görünümün içeriği ve özellikleri hakkında bilgi sağlamanız gerekir. Bu bilgiler bir düğme etiketi gibi basit olabilir ve etkinliğe eklemek istediğiniz ek durum bilgilerini içerebilir.

Bir AccessibilityEvent dosyasındaki bilgileri doldurmak veya değiştirmek için onPopulateAccessibilityEvent() ve onInitializeAccessibilityEvent() yöntemlerini kullanın. Özellikle TalkBack gibi erişilebilirlik hizmetleri tarafından sesli istemlere dönüştürülen etkinlik metin içeriğini eklemek veya değiştirmek için onPopulateAccessibilityEvent() yöntemini kullanın. Etkinlikle ilgili ek bilgileri (ör. görünümün seçim durumu) doldurmak için onInitializeAccessibilityEvent() yöntemini kullanın.

Ayrıca onInitializeAccessibilityNodeInfo() yöntemini uygulayın. Erişilebilirlik hizmetleri, alındıktan sonra bir erişilebilirlik etkinliği oluşturan görünüm hiyerarşisini incelemek ve kullanıcılara uygun geri bildirim sağlamak için bu yöntemle doldurulan AccessibilityNodeInfo nesnelerini kullanır.

Aşağıdaki kod örneğinde, görünümünüzde bu üç yöntemi nasıl geçersiz kılacağınız gösterilmektedir:

Kotlin

override fun onPopulateAccessibilityEvent(event: AccessibilityEvent?) {
    super.onPopulateAccessibilityEvent(event)
    // Call the super implementation to populate its text for the
    // event. Then, add text not present in a super class.
    // You typically only need to add the text for the custom view.
    if (text?.isNotEmpty() == true) {
        event?.text?.add(text)
    }
}

override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) {
    super.onInitializeAccessibilityEvent(event)
    // Call the super implementation to let super classes
    // set appropriate event properties. Then, add the new checked
    // property that is not supported by a super class.
    event?.isChecked = isChecked()
}

override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) {
    super.onInitializeAccessibilityNodeInfo(info)
    // Call the super implementation to let super classes set
    // appropriate info properties. Then, add the checkable and checked
    // properties that are not supported by a super class.
    info?.isCheckable = true
    info?.isChecked = isChecked()
    // You typically only need to add the text for the custom view.
    if (text?.isNotEmpty() == true) {
        info?.text = text
    }
}

Java

@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
    super.onPopulateAccessibilityEvent(event);
    // Call the super implementation to populate its text for the
    // event. Then, add the text not present in a super class.
    // You typically 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(AccessibilityEvent event) {
    super.onInitializeAccessibilityEvent(event);
    // Call the super implementation to let super classes
    // set appropriate event properties. Then, add the new checked
    // property that is not supported by a super class.
    event.setChecked(isChecked());
}

@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
    super.onInitializeAccessibilityNodeInfo(info);
    // Call the super implementation to let super classes set
    // appropriate info properties. Then, add the checkable and checked
    // properties that are not supported by a super class.
    info.setCheckable(true);
    info.setChecked(isChecked());
    // You typically only need to add the text for the custom view.
    CharSequence text = getText();
    if (!TextUtils.isEmpty(text)) {
        info.setText(text);
    }
}

Bu yöntemleri doğrudan özel görünüm sınıfınıza uygulayabilirsiniz.

Özelleştirilmiş bir erişilebilirlik bağlamı sağlayın

Erişilebilirlik hizmetleri, erişilebilirlik etkinliği oluşturan bir kullanıcı arayüzü bileşeninin kapsayıcı görünüm hiyerarşisini inceleyebilir. Bu, erişilebilirlik hizmetlerinin kullanıcılara yardımcı olmak için daha zengin bağlamsal bilgiler sağlamasına olanak tanır.

Erişilebilirlik hizmetlerinin görünüm hiyerarşisinden yeterli bilgi alamadığı durumlar vardır. Takvim denetimi gibi ayrı ayrı iki veya daha fazla tıklanabilir alana sahip olan özel arayüz denetimi buna örnek gösterilebilir. Bu durumda, tıklanabilir alt bölümler görünüm hiyerarşisinin bir parçası olmadığı için hizmetler yeterli bilgi alamaz.

Şekil 1. Seçilebilir gün öğeleri içeren özel takvim görünümü.

Şekil 1'deki örnekte, tüm takvim tek bir görünüm olarak uygulanmıştır. Bu yüzden geliştirici ek bilgi sağlamadıkça erişilebilirlik hizmetleri görünümün içeriği ve kullanıcının görünüm içindeki seçimi hakkında yeterli bilgi almaz. Örneğin, bir kullanıcı 17 etiketli günü tıklarsa erişilebilirlik çerçevesi yalnızca tüm takvim kontrolünün açıklama bilgilerini alır. Bu durumda, TalkBack erişilebilirlik hizmeti "Takvim" veya "Nisan Takvimi"ni duyurur ve kullanıcı hangi günün seçildiğini bilmez.

Çerçeve, bu gibi durumlarda erişilebilirlik hizmetlerine yeterli bağlam bilgisini sağlamak için sanal görünüm hiyerarşisi belirleme olanağı sunar. Sanal görünüm hiyerarşisi, uygulama geliştiricilerin, erişilebilirlik hizmetleri için ekrandaki bilgilerle daha yakından eşleşen tamamlayıcı bir görünüm hiyerarşisi sağlamanın bir yoludur. Bu yaklaşım, erişilebilirlik hizmetlerinin kullanıcılara daha faydalı bağlam bilgileri sağlamasına olanak tanır.

Sanal görünüm hiyerarşisine ihtiyaç duyulabilecek diğer bir durum da, yakından ilişkili işlevlere sahip bir dizi View denetimi içeren kullanıcı arayüzüdür. Bir kontrol üzerindeki bir işlemin, ayrı yukarı ve aşağı düğmeleri olan sayı seçici gibi bir veya daha fazla öğenin içeriğini etkiler. Bu durumda, bir kontroldeki bir işlem diğerinin içeriğini değiştirdiği için erişilebilirlik hizmetleri yeterli bilgileri alamaz ve bu kontrollerin ilişkisi hizmet tarafından anlaşılmayabilir.

Bu durumun üstesinden gelmek için ilgili kontrolleri, kapsayıcı görünümüyle gruplandırın ve kontrollerin sağladığı bilgileri ve davranışı net bir şekilde göstermek için bu kapsayıcıdan sanal görünüm hiyerarşisi sağlayın.

Bir görünüm için sanal görünüm hiyerarşisi sağlamak amacıyla özel görünüm veya görünüm grubunuzda getAccessibilityNodeProvider() yöntemini geçersiz kılın ve AccessibilityNodeProvider uygulamasını döndürün. Destek Kitaplığı'nı ViewCompat.getAccessibilityNodeProvider() yöntemiyle kullanarak sanal bir görünüm hiyerarşisi uygulayabilir ve AccessibilityNodeProviderCompat ile uygulama sağlayabilirsiniz.

Erişilebilirlik hizmetlerine bilgi sağlama ve erişilebilirlik odağını yönetme görevini basitleştirmek için bunun yerine ExploreByTouchHelper öğesini uygulayabilirsiniz. Bir AccessibilityNodeProviderCompat sağlar ve setAccessibilityDelegate çağrısı yaparak görünümün AccessibilityDelegateCompat öğesi olarak eklenebilir. Örnek için bkz. ExploreByTouchHelperActivity. ExploreByTouchHelper, alt görünümü olan SimpleMonthView aracılığıyla CalendarView gibi çerçeve widget'ları tarafından da kullanılır.

Özel dokunma etkinliklerini işleme

Özel görünüm kontrolleri, aşağıdaki örneklerde gösterildiği gibi standart olmayan dokunma etkinliği davranışı gerektirebilir.

Tıklamaya dayalı işlemleri tanımlama

Widget'ınız OnClickListener veya OnLongClickListener arayüzünü kullanıyorsa sistem ACTION_CLICK ve ACTION_LONG_CLICK işlemlerini sizin için yapar. Uygulamanız OnTouchListener arayüzünü temel alan daha özelleştirilmiş bir widget kullanıyorsa tıklamaya dayalı erişilebilirlik işlemleri için özel işleyiciler tanımlayın. Bunu yapmak isterseniz aşağıdaki kod snippet'inde gösterildiği gibi her işlem için replaceAccessibilityAction() yöntemini çağırın:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    // Assumes that the widget is designed to select text when tapped, and selects
    // all text when tapped and held. In its strings.xml file, this app sets
    // "select" to "Select" and "select_all" to "Select all".
    ViewCompat.replaceAccessibilityAction(
        binding.textSelectWidget,
        ACTION_CLICK,
        getString(R.string.select)
    ) { view, commandArguments ->
        selectText()
    }

    ViewCompat.replaceAccessibilityAction(
        binding.textSelectWidget,
        ACTION_LONG_CLICK,
        getString(R.string.select_all)
    ) { view, commandArguments ->
        selectAllText()
    }
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    // Assumes that the widget is designed to select text when tapped, and select
    // all text when tapped and held. In its strings.xml file, this app sets
    // "select" to "Select" and "select_all" to "Select all".
    ViewCompat.replaceAccessibilityAction(
            binding.textSelectWidget,
            ACTION_CLICK,
            getString(R.string.select),
            (view, commandArguments) -> selectText());

    ViewCompat.replaceAccessibilityAction(
            binding.textSelectWidget,
            ACTION_LONG_CLICK,
            getString(R.string.select_all),
            (view, commandArguments) -> selectAllText());
}

Özel tıklama etkinlikleri oluşturma

Özel kontroller, ACTION_DOWN ve ACTION_UP etkinliklerini algılamak ve özel bir tıklama etkinliğini tetiklemek için onTouchEvent(MotionEvent) işleyici yöntemini kullanabilir. Bu özel tıklama etkinliğini işleyen kod, erişilebilirlik hizmetleriyle uyumluluğu sağlamak için aşağıdakileri yapmalıdır:

  1. Yorumlanan tıklama işlemi için uygun bir AccessibilityEvent oluşturun.
  2. Dokunmatik ekran kullanamayan kullanıcılar için özel tıklama işlemini gerçekleştirmek amacıyla erişilebilirlik hizmetlerini etkinleştirin.

Bu gereksinimleri verimli bir şekilde işlemek için kodunuzun performClick() yöntemini geçersiz kılması gerekir. Bu yöntem, bu yöntemin süper uygulamasını çağırmalı ve ardından tıklama etkinliği için gerekli olan işlemleri yürütmelidir. Özel tıklama işlemi algılandığında, bu kod performClick() yönteminizi çağırmalıdır. Aşağıdaki kod örneği bu kalıbı gösterir.

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
                // enable accessibility services to
                // perform this action for a user who can't
                // tap 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
                                    // enable accessibility services to
                                    // perform this action for a user who can't
                                    // tap 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;
    }
}

Yukarıdaki kalıp, bir erişilebilirlik etkinliği oluşturmak için performClick() yöntemini kullanarak özel tıklama etkinliğinin erişilebilirlik hizmetleriyle uyumlu olmasına yardımcı olur ve erişilebilirlik hizmetlerinin özel tıklama etkinliğini gerçekleştiren bir kullanıcı adına hareket etmesi için bir giriş noktası sağlar.