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: ,Εάν μια ιστοσελίδα μπορεί να πλοηγηθεί διαδοχικά και η σειρά εστίασης επηρεάζει το νόημα, τότε η εστίαση πρέπει να ακολουθεί μια σειρά που διατηρεί το νόημα και τη δυνατότητα ελέγχου". Εξαίρεση: δυναμικό περιεχόμενο όπου η εστίαση μπορεί να μεταπηδήσει για να προσελκύσει την προσοχή (προειδοποιήσεις, modal παράθυρα).

Γιατί το Focus Order είναι κρίσιμο για την προσβασιμότητα

Ο χρήστης Switch Control (άτομα με κινητικές αναπηρίες) μετακινείται αυτόματα μεταξύ στοιχείων — κύκλο με τον κύκλο. Εάν η σειρά παραβιαστεί, ο χρήστης ξοδεύει 3 φορές περισσότερο χρόνο για να ολοκληρώσει μια φόρμα. Σύμφωνα με το Deque University, 2024, η σωστή σειρά εστίασης μειώνει τον χρόνο συμπλήρωσης φόρμας κατά 60% για χρήστες βοηθητικών τεχνολογιών.

Focus Order και modal παράθυρα

Ιδιαίτερη προσοχή — στα modal παράθυρα. Μετά το άνοιγμα ενός modal παραθύρου, η εστίαση πρέπει άμεσα να μετακινηθεί στο πρώτο διαδραστικό στοιχείο μέσα στο modal (συνήθως το κουμπί ,Κλείσιμο" ή ,Επιβεβαίωση"). Μετά το κλείσιμο — να επιστρέψει στο στοιχείο που κάλεσε το modal παράθυρο. Αυτή είναι απαίτηση του 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 η σειρά εστίασης είναι δυναμική — καθορίζεται από τον adapter. Εάν τα κελιά έχουν σύνθετη δομή, ορίστε descendantFocusability = ,beforeDescendants" και καθορίστε τη σειρά στον κόμβο του στοιχείου λίστας. Για Jetpack Compose η σειρά εστίασης ορίζεται μέσω Modifier.focusOrder() και FocusOrder. Προτεραιότητα: previous (θυγατρικό), next (επόμενο), custom key.

TouchDelegate, hit area και περιοχή εστίασης

Εάν ένα στοιχείο είναι πολύ μικρό για εστίαση (μικρότερο από 44pt), αυξήστε την hit area μέσω 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, η αόρατη εστίαση είναι η δεύτερη συχνότερη αιτία αποτυχίας σε έλεγχο προσβασιμότητας.

Modal παράθυρα — η εστίαση παραμένει στο περιεχόμενο φόντου μετά το άνοιγμα modal παραθύρου. Στο iOS η modal προβολή συλλαμβάνει αυτόματα την εστίαση εάν έχει οριστεί modalPresentationStyle = .pageSheet. Στο Android χρησιμοποιήστε setFocusable(true) στον περιέκτη διαλόγου.

Focus trap (παγίδα εστίασης)

Αντίστροφο πρόβλημα: η εστίαση παγιδεύεται μέσα στο modal παράθυρο και δεν μπορεί να βγει (εκτός από το κλείσιμο). Αυτό επιτρέπεται μόνο για modal παράθυρα — ο χρήστης πρέπει συνειδητά να κλείσει το παράθυρο. Για κανονικές οθόνες, το focus trap είναι κρίσιμο σφάλμα. Λύση: βεβαιωθείτε ότι το τελευταίο στοιχείο του modal παραθύρου (κουμπί ,Κλείσιμο") επιστρέφει την εστίαση πίσω.

Προσαρμοσμένες οθόνες και προγραμματισμένη εστίαση

Για προσαρμοσμένες οθόνες (χάρτες, καμβάδες, παιχνίδια) η αυτόματη γεωμετρική σειρά δεν εφαρμόζεται. Ο προγραμματιστής πρέπει να χτίσει το δέντρο προσβασιμότητας χειροκίνητα. Στο iOS για αυτό το σκοπό γίνεται παράκαμψη της μεθόδου UIAccessibilityContainer.

Παράδειγμα για προσαρμοσμένο καμβά:

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

    override var accessibilityElements: [Any]? {
        get {
            // Ταξινομούμε τα σχήματα κατά Z-index, όχι κατά γεωμετρία
            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
}

Για δυναμικές λίστες (chat, ροή ειδήσεων) μετά την προσθήκη στοιχείου καλέστε μετακίνηση εστίασης στο πρώτο νέο στοιχείο. Στο 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 και accessibility

Για κινούμενες οθόνες (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-test σεναρίου: συμπληρώστε τη φόρμα βήμα προς βήμα (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" στο ριζικό στοιχείο και ρυθμίστε τη σειρά στον adapter μέσω 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. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης