Özel görünümleri daha erişilebilir hale getirme (Görünümler)

Kavramlar ve Jetpack Compose uygulaması

Uygulamanızda özel görünüm bileşeni kullanılıyorsa 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 artırabilir:

  • Yön kontrolü tıklamalarını işleyin.
  • Erişilebilirlik 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 denetleyicisi tıklamalarını işleme

Çoğu cihazda, yön denetleyicisiyle bir görünümü tıkladığınızda, ön planda olan görünüme KeyEvent ile KEYCODE_DPAD_CENTER gönderilir. Tüm standart Android görünümleri KEYCODE_DPAD_CENTER öğesini uygun şekilde işler. Özel bir Viewkontrolü oluştururken bu etkinliğin, görünüme dokunmatik ekranda dokunmayla aynı etkiye sahip olduğundan emin olun.

Özel kontrolünüz, KEYCODE_ENTER KEYCODE_DPAD_CENTER etkinliğini KEYCODE_DPAD_CENTER ile aynı şekilde işlemelidir. Bu sayede kullanıcılar tam klavyeyle daha kolay etkileşim kurabilir.

Erişilebilirlik 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, ek geri bildirim ve istemler oluşturmak için bu etkinliklerdeki bilgileri kullanan erişilebilirlik hizmetleri tarafından işlenir. Erişilebilirlik yöntemleri, View ve View.AccessibilityDelegate sınıflarının bir parçasıdır. Yöntemler şunlardır:

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(), ardından bu görünümün her bir alt öğesi için dispatchPopulateAccessibilityEvent() yöntemini çağırır.
onInitializeAccessibilityEvent()
Sistem, görünümün durumu hakkında metin içeriğinin ötesinde ek bilgi edinmek için bu yöntemi ç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 geçersiz kılın ve görünümünüzle ilgili ek bilgileri (ör. şifre alanı türü, onay kutusu türü veya kullanıcı etkileşimi ya da geri bildirim sağlayan durumlar) bu yöntemi kullanarak ayarlayın. Bu yöntemi geçersiz kılarsanız üst sınıfın uygulamasını çağırın ve yalnızca üst 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ı, standart bir görünüm özelliklerine sahiptir. 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ın ve görünümünüzle ilgili ek bilgileri bu yöntem tarafından işlenen AccessibilityNodeInfo nesnesine ayarlayın.
onPopulateAccessibilityEvent()
Bu yöntem, görünümünüz için AccessibilityEvent'nin konuşulan metin istemini ayarlar. Görünüm, erişilebilirlik etkinliği oluşturan bir görünümün alt öğesi olduğunda da çağrılır.
onRequestSendAccessibilityEvent()
Sistem, görünümünüzün bir alt öğesi bir AccessibilityEvent oluşturduğunda bu yöntemi çağırır. Bu adım, ebeveyn görünümünün erişilebilirlik etkinliğini ek bilgilerle değiştirmesine olanak tanır. Bu yöntemi yalnızca özel görünümünüzde çocuk ekranı olabiliyorsa ve ebeveyn görünümü, erişilebilirlik hizmetleri için yararlı olan erişilebilirlik etkinliğine bağlam bilgisi sağlayabiliyorsa uygulayın.
sendAccessibilityEvent()
Kullanıcı bir görünümde 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, arama kodunun cihazda erişilebilirliğin etkinleştirilip etkinleştirilmediğini (AccessibilityManager.isEnabled()) doğrudan kontrol etmesi gerektiğinde kullanılır. Bu yöntemi uygularsanız sistem ayarından bağımsız olarak aramayı erişilebilirlik etkinleştirilmiş gibi gerçekleştirin. Genellikle özel bir görünüm için bu yöntemi uygulamanız gerekmez.

Erişimi desteklemek için önceki erişim yöntemlerini geçersiz kılın ve doğrudan özel görünüm sınıfınızda 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öntemleri uygulama hakkında daha fazla bilgi için erişilebilirlik etkinliklerini doldurma bölümüne bakın.

Erişilebilirlik etkinlikleri gönderme

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

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 kaydırma çubuğu değeri her değiştiğinde özel görünümünüz TYPE_VIEW_TEXT_CHANGED etkinliğini 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 doldurma

Her AccessibilityEvent, görünümün mevcut durumunu açıklayan bir dizi zorunlu özelliğe sahiptir. Bu özellikler arasında görünümün sınıf adı, içerik açıklaması ve işaretli durumu gibi öğeler yer alır. Her etkinlik türü için gereken özellikler, AccessibilityEventreferans dokümanlarında açıklanmıştır.

View uygulaması, bu zorunlu özellikler için varsayılan değerler sağlar. Sınıf adı ve etkinlik zaman damgası gibi 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 vermeniz gerekir. Bu bilgiler, bir düğme etiketi kadar basit olabilir ve etkinliğe eklemek istediğiniz ek durum bilgilerini içerebilir.

AccessibilityEvent içindeki bilgileri doldurmak veya değiştirmek için onPopulateAccessibilityEvent() ve onInitializeAccessibilityEvent() yöntemlerini kullanın. onPopulateAccessibilityEvent() yöntemini özellikle etkinliğin metin içeriğini eklemek veya değiştirmek için kullanın. Bu içerik, TalkBack gibi erişilebilirlik hizmetleri tarafından sesli istemlere dönüştürülür. Görünümün seçim durumu gibi etkinlik hakkında ek bilgiler doldurmak için onInitializeAccessibilityEvent() yöntemini kullanın.

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

Aşağıdaki kod örneğinde, bu üç yöntemin görünümünüzde nasıl geçersiz kılınacağı 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ızda uygulayabilirsiniz.

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

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

Erişilebilirlik hizmetlerinin görünüm hiyerarşisinden yeterli bilgi alamadığı durumlar olabilir. Buna örnek olarak, takvim kontrolü gibi iki veya daha fazla ayrı tıklanabilir alanı olan özel bir arayüz kontrolü verilebilir. Bu durumda, tıklanabilir alt bölümler görünüm hiyerarşisinin bir parçası olmadığından hizmetler yeterli bilgi alamaz.

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

Şekil 1'deki örnekte, takvimin tamamı tek bir görünüm olarak uygulanır. Bu nedenle, geliştirici ek bilgi sağlamadığı sürece erişilebilirlik hizmetleri, görünümün içeriği ve kullanıcının görünümdeki seçimi hakkında yeterli bilgi almaz. Örneğin, bir kullanıcı 17 olarak etiketlenen güne tıkladığında erişilebilirlik çerçevesi yalnızca takvim kontrolünün tamamı için açıklama bilgilerini alır. Bu durumda TalkBack erişilebilirlik hizmeti "Takvim" veya "Nisan Takvimi" şeklinde duyuru yapıyor ve kullanıcı hangi günün seçildiğini bilmiyor.

Bu gibi durumlarda erişilebilirlik hizmetleri için yeterli bağlam bilgisi sağlamak amacıyla çerçeve, sanal görünüm hiyerarşisi belirtmenin bir yolunu sunar. Sanal görünüm hiyerarşisi, uygulama geliştiricilerin erişilebilirlik hizmetlerine ek bir görünüm hiyerarşisi sağlamasının bir yoludur. Bu hiyerarşi, ekrandaki bilgilerle daha yakından eşleşir. 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şisinin gerekebileceği bir diğer durum da, bir dizi View kontrol içeren bir kullanıcı arayüzüdür. Bu kontrollerin işlevleri yakından ilişkilidir ve bir kontrol üzerinde yapılan işlem, bir veya daha fazla öğenin içeriğini etkiler. Örneğin, ayrı yukarı ve aşağı düğmeleri olan bir sayı seçici. Bu durumda, bir kontrol üzerinde yapılan işlem başka bir kontrolün içeriğini değiştirdiğinden ve bu kontrollerin ilişkisi hizmet tarafından anlaşılamayabileceğinden erişilebilirlik hizmetleri yeterli bilgi alamaz.

Bu durumu ele almak için ilgili kontrolleri kapsayan bir görünümle gruplandırın ve kontroller tarafından sağlanan bilgileri ve davranışları net bir şekilde göstermek için bu kapsayıcıdan sanal bir 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 üzere özel görünümünüzde veya görünüm grubunuzda getAccessibilityNodeProvider() yöntemini geçersiz kılın ve AccessibilityNodeProvider uygulamasını döndürün. ViewCompat.getAccessibilityNodeProvider() yöntemiyle Destek Kitaplığı'nı kullanarak sanal bir görünüm hiyerarşisi uygulayabilir ve AccessibilityNodeProviderCompat ile bir 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 uygulayabilirsiniz. AccessibilityNodeProviderCompat sağlar ve setAccessibilityDelegate çağrılarak görünümün AccessibilityDelegateCompat olarak eklenebilir. Örnek için ExploreByTouchHelperActivity konusuna bakın. ExploreByTouchHelper, SimpleMonthView çocuk ekranı 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 gerçekleştirir. Uygulamanız, OnTouchListener arayüzünü kullanan daha özelleştirilmiş bir widget kullanıyorsa tıklamaya dayalı erişilebilirlik işlemleri için özel işleyiciler tanımlayın. Bunu yapmak için 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 bir kontrol, onTouchEvent(MotionEvent) listener yöntemini kullanarak ACTION_DOWN ve ACTION_UP etkinliklerini algılayabilir ve özel bir tıklama etkinliğini tetikleyebilir. Erişilebilirlik hizmetleriyle uyumluluğu korumak için bu özel tıklama etkinliğini işleyen kodun aşağıdakileri yapması gerekir:

  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 üzere erişilebilirlik hizmetlerini etkinleştirin.

Bu koşulları verimli bir şekilde işlemek için kodunuzun performClick() yöntemini geçersiz kılması gerekir. Bu yöntem, bu yöntemin üst uygulamasını çağırmalı ve ardından tıklama etkinliği tarafından gerekli olan tüm 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ğinde bu kalıp gösterilmektedir.

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, erişilebilirlik etkinliği oluşturmak için performClick() yöntemi kullanılarak 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ğlanarak özel tıklama etkinliğinin erişilebilirlik hizmetleriyle uyumlu olmasını sağlamaya yardımcı olur.