Published on

Swift'da qulaylik (Accessibility): VoiceOver

Authors

VoiceOver β€” ko'rish qobiliyati cheklangan foydalanuvchilar uchun mo'ljallangan, ilovani ekranga qaramay ishlatish imkonini beruvchi tizim. VoiceOver yoqilganda foydalanuvchi:

  • O'ngga/chapga siljitib β†’ keyingi/oldingi elementga o'tadi
  • Yuqori/pastga siljitib β†’ bo'limdan bo'limga sakraydi
  • Biror elementga bossa β†’ uni tanlaydi
  • Ikki marta bossa β†’ tanlangan elementni faollashtiradi

VoiceOver'ni yoqish: Siri β€” "Hey Siri, turn on VoiceOver". O'chirish: "Hey Siri, turn off VoiceOver".


Asosiy qoida: Native komponentlar eng yaxshisi

Native komponentlar (Toggle, Button va boshqalar) VoiceOver'ni avtomatik qo'llab-quvvatlaydi β€” ular element nomini, turini (button, switch) va amalini o'z-o'zidan e'lon qiladi. Maxsus (custom) komponentlar esa qo'shimcha kod talab qiladi.


Ekran tuzilmasi

@State private var isActive: Bool = false

var body: some View {
    NavigationStack {
        Form {
            // 1-bo'lim: Sozlamalar
            Section(header: Text("Preferences")) {
                // Native toggle (avtomatik accessible)
                Toggle("Volume", isOn: $isActive)

                // Maxsus toggle (qo'lda qo'shish kerak)
                HStack {
                    Text("Volume")
                    Spacer()
                    Text(isActive ? "On" : "Off")
                }
                .background(Color.black.opacity(0.001)) // tapping maydoni uchun
                .onTapGesture {
                    isActive.toggle()
                }
            }

            // 2-bo'lim: Ilovalar
            Section(header: Text("Application")) {
                Button("Favorites") {}

                Button(action: {}) {
                    HStack {
                        Image(systemName: "heart.fill")
                        Text("Favorites")
                    }
                }

                Text("Favorites")
                    .onTapGesture {}
            }
        }
        .navigationTitle("Settings")
    }
}

1. accessibilityElement(children: .combine) β€” elementlarni birlashtirish

Native toggle bosilganda VoiceOver aytadi: "Volume, switch button, off, double tap to toggle setting". Ajoyib.

Maxsus HStack bosilganda esa faqat: "Volume". Yomon β€” u HStack ichidagi "Off" matnini alohida element sifatida ko'radi.

Yechim β€” bolalar elementlarni birlashtirish:

HStack {
    Text("Volume")
    Spacer()
    Text(isActive ? "On" : "Off")
}
.onTapGesture { isActive.toggle() }
.accessibilityElement(children: .combine)

Endi ikkisi bitta element sifatida eshitiladi: "Volume, off".


2. accessibilityAddTraits β€” element turini belgilash

Element tugma ekanligini bildirish:

.accessibilityAddTraits(.isButton)

Endi: "Volume, off, button" β€” foydalanuvchi bu elementni bosishi mumkinligini biladi.


3. accessibilityHint β€” qo'shimcha yo'riqnoma

Bosganda nima bo'lishi haqida qo'shimcha ma'lumot:

.accessibilityHint("Double tap to toggle setting")

Endi: "Volume, off, button β€” double tap to toggle setting".


4. accessibilityValue + accessibilityHidden β€” maxsus qiymat

Ba'zan HStack ichidagi matn "true" / "false" kabi noaniq bo'lishi mumkin. Bunday holda shu matnni yashirib, o'rniga tushunarli qiymat beramiz:

HStack {
    Text("Volume")
    Spacer()
    Text(isActive ? "true" : "false")
        .accessibilityHidden(true)  // yashir
}
.accessibilityElement(children: .combine)
.accessibilityAddTraits(.isButton)
.accessibilityValue(isActive ? "Volume is on" : "Volume is off")  // o'rniga
.accessibilityHint("Double tap to toggle setting")
.onTapGesture { isActive.toggle() }

Endi eshitiladi: "Volume is off, button β€” double tap to toggle setting" β€” aniq inglizcha jumla.


5. accessibilityAction β€” maxsus harakat

Accessibility harakati odatdagi tap gesture'dan alohida bo'lishi mumkin:

.accessibilityAction {
    isActive.toggle()
}

Ko'p hollarda tap gesture bilan bir xil, ammo buni eksplitsit qo'shish yaxshi amaliyot.


6. accessibilityLabel β€” element nomini o'zgartirish

Tizim belgisi (heart.fill) VoiceOver tomonidan "love" deb o'qiladi. Buni "Favorites" qilib o'zgartirish:

Button(action: {}) {
    Image(systemName: "heart.fill")
}
.accessibilityLabel("Favorites")

Endi: "Favorites, button".


7. accessibilityRemoveTraits β€” trait'larni olib tashlash

Ba'zan elementdan "image" traitini olib tashlab, "button" qo'shish kerak bo'ladi:

.accessibilityRemoveTraits(.isImage)
.accessibilityAddTraits(.isButton)

8. accessibilityAddTraits(.isHeader) β€” bo'lim sarlavhasi

VoiceOver'da rotor yordamida foydalanuvchi sarlavhadan-sarlavhaga sakray oladi. Native Section(header:) bu traitni avtomatik oladi, ammo maxsus matnlar olmaydi:

Text("Content")
    .accessibilityAddTraits(.isHeader)

Endi foydalanuvchi rotor'da "headings" rejimida bo'lsa, pastga siljitib "Preferences β†’ Application β†’ Content" sarlavhalari orasida sakray oladi.


9. Scroll view ichidagi katakchalar (to'liq misol)

Gorizontal scroll view'dagi har bir katakning to'liq accessibility kodi:

ForEach(0..<10) { index in
    VStack {
        Image("steve-jobs")
            .resizable()
            .scaledToFill()
            .frame(width: 100, height: 100)
            .cornerRadius(10)

        Text("Item: \(index)")
    }
    .onTapGesture {}
    .accessibilityElement(children: .combine)       // birlashtir
    .accessibilityAddTraits(.isButton)              // button
    .accessibilityLabel("Item \(index). Image of Steve Jobs.") // aniq nom
    .accessibilityHint("Double tap to open")       // yo'riqnoma
}

Hozircha bosilganda VoiceOver faqat "Steve Jobs image... Steve Jobs image..." der edi. Endi esa: "Item 2, image of Steve Jobs, button β€” double tap to open".


Screen Curtain bilan sinash

VoiceOver yoqilgan holda uch barmoq bilan ekranni uch marta bossang, Screen Curtain yoqiladi β€” ekran butunlay qorayadi, go'yo ko'rish imkoni yo'qday. Shu holatda ilovangizni ishlatib ko'ring β€” foydalanuvchi qulay foydalana oladimi?


Xulosa: amaliy ketma-ketlik

VaziyatYechim
Native Toggle, ButtonHech narsa qilmaslik β€” avtomatik
Maxsus HStack/VStack.accessibilityElement(children: .combine)
Elementning turi noaniq.accessibilityAddTraits(.isButton / .isHeader)
Matn noaniq ("true").accessibilityHidden(true) + .accessibilityValue(...)
Belgi nomi noto'g'ri ("love").accessibilityLabel("Favorites")
Sarlavha emas, lekin sarlavha.accessibilityAddTraits(.isHeader)
Yo'riqnoma kerak.accessibilityHint("Double tap to...")

Asosiy tavsiya: imkon qadar native komponentlardan foydalaning. Majbur bo'lsangiz, shu jadvaldan foydalanib qo'lda qo'shing β€” bu bir-ikki daqiqa vaqt oladi va juda ko'p foydalanuvchi uchun ilovangizni ishlatish imkonini beradi.

Buy mea coffee