Focus Order — какво е, принципи и как да го настроите в мобилните приложения

Автор: IT Sectr Публикувано: 2026-05-16 Време за четене: 9 мин

Focus Order е последователността, в която елементите на интерфейса получават фокус при навигация с клавиатура, Switch Control, VoiceOver или TalkBack. В мобилните приложения редът на фокуса определя как потребителят се придвижва между контролите с жестове или бутони. Според W3C WCAG 2.2, Success Criterion 2.4.3, 2023, фокусът трябва да следва логичен ред, който запазва смисъла на съдържанието. Нарушаването на този принцип е една от честите причини за провал на одита за достъпност.

Основни моменти

  • Focus Order — редът на обхождане на интерактивните елементи при навигация с клавиатура или screen reader
  • Фокусът трябва да следва визуалния ред (отляво надясно, отгоре надолу) и да запазва логиката на съдържанието
  • В iOS редът се регулира чрез shouldGroupAccessibilityElement и масива accessibilityElements
  • В Android атрибутите nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight задават съседите на фокуса
  • Персонализираните екрани (карти, платна, игри) изискват програмно управление на фокуса чрез UIAccessibilityPostNotification

Какво е Focus Order в достъпността

Focus Order е последователността, в която потребителят се придвижва между интерактивните елементи с помощта на алтернативни методи за въвеждане: клавиатура (Tab), Switch Control (стъпка по стъпка), VoiceOver (жест надясно/наляво) или TalkBack. За разлика от мишката или сензорния екран, където потребителят избира елемента директно, фокусната навигация е линейна — всяка стъпка премества фокуса върху следващия елемент.

Според Apple HIG, 2024, VoiceOver използва реда на елементите в дървото за достъпност, което се изгражда въз основа на визуалното разположение: горен ляв ъгъл → долен десен ъгъл. Ако екранът съдържа сложна подредба (колони, Grid, ZStack), дървото може да не съответства на визуалния ред.

Принципът на WCAG 2.4.3: „Ако уеб страницата може да се навигира последователно по секции и редът на фокуса влияе на смисъла, то фокусът трябва да следва ред, който запазва смисъла и възможността за управление”. Изключение: динамично съдържание, при което фокусът може да скача, за да привлече вниманието (предупреждения, модални прозорци).

Защо Focus Order е критичен за достъпността

Потребителят на Switch Control (хора с двигателни увреждания) се придвижва между елементите автоматично — цикъл след цикъл. Ако редът е нарушен, потребителят отделя 3 пъти повече време за попълване на формуляр. Според Deque University, 2024, коректният Focus Order намалява времето за попълване на формуляри с 60% за потребителите на помощни технологии.

Focus Order и модалните прозорци

Особено внимание се отделя на модалните прозорци. След отваряне на модален прозорец фокусът трябва незабавно да се премести върху първия интерактивен елемент вътре в модала (обикновено бутонът „Затвори” или „Потвърди”). След затваряне — да се върне върху елемента, който е извикал модалния прозорец. Това е изискване на WCAG 2.4.3 и същевременно често срещана грешка.

iOS: управление на реда на фокуса

В iOS VoiceOver автоматично изгражда реда на базата на геометрията: елементите се сортират по Y, след това по X. За екрани със сложна структура този ред може да е неправилен — разработчикът трябва да се намеси.

Основните инструменти:

  • shouldGroupAccessibilityElement — обединява дъщерните елементи в един логичен блок
  • accessibilityElements — масив, който задава персонализиран ред на дъщерните елементи
  • UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element) — програмно преместване на фокуса

Пример за задаване на персонализиран ред за карта на продукт:

swift
class ProductCardView: UIView {
    let titleLabel = UILabel()
    let priceLabel = UILabel()
    let buyButton = UIButton()

    override var accessibilityElements: [Any]? {
        get {
            return [titleLabel!, priceLabel!, buyButton!]
        }
        set {}
    }
}

За програмно преместване на фокуса след действие:

swift
UIAccessibility.post(
    notification: .layoutChanged,
    argument: newlyAddedItem
)

shouldGroupAccessibilityElement на практика

Свойството shouldGroupAccessibilityElement е полезно за картите в колекции. Ако зададете true на родителската карта, VoiceOver възприема цялата карта като един елемент. Потребителят може да докосне два пъти, за да активира цялата карта, или да настрои ротора за навигация вътре в нея. Препоръчва се за UICollectionViewCell и UITableViewCell.

Android: атрибути на посоката на фокуса

В Android TalkBack също използва геометричния ред, но приоритет се дава на изричните атрибути nextFocus*. Тези атрибути се задават в XML или програмно:

АтрибутПредназначениеПример
nextFocusDownЕлемент при навигация надолу@+id/field_email
nextFocusUpЕлемент при навигация нагоре@+id/field_name
nextFocusLeftЕлемент отляво@+id/btn_back
nextFocusRightЕлемент отдясно@+id/btn_next

Пример за формуляр за регистрация:

xml
<EditText
    android:id="@+id/field_email"
    android:nextFocusDown="@+id/field_password" />

<EditText
    android:id="@+id/field_password"
    android:nextFocusDown="@+id/btn_submit" />

За RecyclerView редът на фокуса е динамичен — определя се от адаптера. Ако клетките имат сложна структура, задайте descendantFocusability = "beforeDescendants" и определете реда във възела на елемента от списъка. За Jetpack Compose редът на фокуса се задава чрез Modifier.focusOrder() и FocusOrder. Приоритет: previous (дъщерен), next (следващ), custom key.

TouchDelegate, зона за докосване и област на фокуса

Ако елементът е твърде малък за фокус (по-малък от 44pt), увеличете зоната за докосване чрез TouchDelegate в iOS или minWidth/minHeight в Android. Според Google Material Design, 2024, минималната зона за докосване е 48×48dp. VoiceOver и TalkBack фокусират върху bounding box на елемента. Елементите с размер под 30pt може да са недостъпни за фокус с жест — потребителят физически не може да ги достигне с пръст.

Типични нарушения на WCAG 2.4.3

Скачащ фокус — когато след действие (например изтриване на елемент) фокусът се премества в началото на списъка или върху системния бутон „Назад”. Потребителят на VoiceOver губи контекста. Решение: програмно преместете фокуса върху елемента, най-близо до изтрития.

Невидим фокус — елементът получава фокус, но няма визуален индикатор (потребителите на клавиатура не виждат къде са). В iOS проверявайте UIAccessibility.isVoiceOverRunning за персонализирани индикатори. Според Deque University, 2024, невидимият фокус е втората по честота причина за провал на одита за достъпност.

Модални прозорци — фокусът остава върху фоновия контент след отваряне на модален прозорец. В iOS модалният view автоматично улавя фокуса, ако е зададен modalPresentationStyle = .pageSheet. В Android използвайте setFocusable(true) върху контейнера на диалога.

Focus trap (капан на фокуса)

Обратният проблем: фокусът засяда вътре в модалния прозорец и не може да излезе (освен при затваряне). Това е допустимо само за модалните прозорци — потребителят трябва съзнателно да затвори прозореца. За обикновените екрани focus trap е критична грешка. Решение: уверете се, че последният елемент на модалния прозорец (бутонът „Затвори”) връща фокуса обратно.

Персонализирани екрани и програмен фокус

За персонализираните екрани (карти, платна, игри) автоматичният геометричен ред не е приложим. Разработчикът трябва да изгради дървото за достъпност ръчно. В iOS за това се предефинира методът UIAccessibilityContainer.

Пример за персонализирано платно:

swift
class CanvasView: UIView {
    var shapes: [ShapeView] = []

    override var accessibilityElements: [Any]? {
        get {
            // Сортираме фигурите по Z-индекс, а не по геометрия
            return shapes.sorted { $0.zIndex < $1.zIndex }
        }
        set {}
    }
}

В Android за персонализиран View предефинирайте onInitializeAccessibilityNodeInfo:

kotlin
override fun onInitializeAccessibilityNodeInfo(
    info: AccessibilityNodeInfo
) {
    super.onInitializeAccessibilityNodeInfo(info)
    info.addChild(firstElement)
    info.addChild(secondElement)
    info.isFocusable = true
}

За динамичните списъци (чат, новинарска емисия) след добавяне на елемент извикайте преместване на фокуса върху първия нов елемент. В iOS: UIAccessibility.post(notification: .layoutChanged, argument: newMessage). В Android: sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED).

AccessibilityFrame и геометрията на фокуса

iOS автоматично определя областта на фокуса на базата на frame на елемента. Ако елементът има трансформация (transform, rotation), VoiceOver може да фокусира върху неправилната област. Изрично задайте accessibilityFrame в координатите на екрана: element.accessibilityFrame = UIAccessibility.convertToScreenCoordinates(element.bounds, in: element). Това гарантира, че VoiceOver ще подчертае правилната област.

UIKit Dynamics и достъпност

За анимираните екрани (UIKit Dynamics, Lottie, SpriteKit) програмният фокус е особено важен. VoiceOver не може да изгради дърво за достъпност за динамично движещите се елементи. Задавайте isAccessibilityElement = false върху контейнерите на анимацията и true само върху интерактивните елементи вътре.

Тестване на реда на фокуса

Ръчно тестване: включете VoiceOver (iOS) или TalkBack (Android), прекарайте с жест надясно по цялата последователност. Фокусът трябва да следва визуалния ред — отляво надясно, отгоре надолу. Всеки интерактивен елемент трябва да получи фокус точно веднъж.

Автоматизираното тестване е трудно, но възможно:

swift
func testKeyboardFocusOrder() {
    let app = XCUIApplication()
    app.launch()
    app.textFields["Email"].tap()
    // Tab — само с апаратна клавиатура
}

За Android използвайте Accessibility Testing Framework:

kotlin
@Test
fun testFocusOrder() {
    onView(withId(R.id.fieldEmail))
        .check(matches(isFocusable()))
    onView(withId(R.id.fieldEmail))
        .perform(focus())
    onView(withId(R.id.fieldPassword))
        .check(matches(isFocused()))
}

Най-надеждният метод е UI тест на сценария: попълнете формуляра стъпка по стъпка (Email → Парола → Изпрати), проверявайки, че всяка стъпка завършва успешно. Ако редът на фокуса е нарушен, сценарият ще се провали при опит за взаимодействие с елемент извън фокуса.

Xcode Accessibility Inspector за дебъгване

Инструментът Accessibility Inspector в Xcode показва пълното дърво за достъпност. Можете да преминете през елементите в реда на VoiceOver и да видите точния път на фокуса. Използвайте раздела „Audit” за автоматично търсене на нарушения на Focus Order.

Често задавани въпроси

Какво е WCAG 2.4.3 и какви изисквания има към фокуса?

WCAG 2.4.3 (Focus Order) — критерий за успех от ниво A. Изисква редът на фокуса да запазва смисъла на съдържанието при последователна навигация. Нарушението се счита за критично и блокира сертификацията.

Как да задам ред на фокуса за елементи, скрити зад анимация?

Скритите елементи трябва да имат isAccessibilityElement = false в iOS или visibility = gone/invisible в Android. При появата им — програмно преместете фокуса чрез UIAccessibility.post(notification: .layoutChanged).

Каква е разликата между фокуса в iOS и Android?

iOS управлява чрез accessibilityElements и shouldGroupAccessibilityElement, Android — чрез атрибутите nextFocus* и AccessibilityNodeInfo. Принципът е един и същ: геометричен ред по подразбиране с възможност за предефиниране.

Какво да направя, ако RecyclerView има неправилен ред?

Задайте descendantFocusability = "beforeDescendants" върху кореновия елемент и настройте реда в адаптера чрез onInitializeAccessibilityNodeInfo за всяка клетка.

Как да проверя фокуса без VoiceOver?

Свържете апаратна клавиатура чрез Bluetooth или USB. В iOS натиснете Tab за преместване на фокуса. В Android включете TalkBack и използвайте клавишите Tab и стрелките.

Обобщение

  • Focus Order — последователността на обхождане на елементите при навигация с клавиатура или screen reader; основава се на WCAG 2.4.3
  • Фокусът трябва да следва визуалния ред (отляво надясно, отгоре надолу) — автоматично във VoiceOver и TalkBack
  • В iOS редът се регулира чрез accessibilityElements и shouldGroupAccessibilityElement
  • В Android се използват атрибутите nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight
  • Персонализираните екрани (карти, платна) изискват програмно управление на фокуса чрез UIAccessibilityPostNotification
  • Нарушаването на реда е критична грешка на WCAG 2.4.3; потребителите губят контекста и не могат да завършат сценария
  • Тествайте фокуса чрез жестове на VoiceOver/TalkBack, апаратна клавиатура и автоматизирани сценарии

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също