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