---
title: Erişilebilirlik
source: 'https://academia.sh/tr/kurslar/swiftui/erisilebilirlik'
course: 'SwiftUI ile Arayüz'
language: tr
updated: '2026-10-21T05:03:13+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Erişilebilirlik bilgisinin etiket, özellik ve sistem tercihi olarak üç ayrı yoldan geldiğini ayırır'
    - 'Dinamik yazı boyutunun yalnız onu okuyan görünümü ortam tetiğiyle yeniden hesaplattığını ölçer'
    - 'Hareket azaltma tercihinin ortam değeri olarak okunduğunu ölçer'
    - 'Sabit dizeyle verilen etiketin hiçbir değeri okumadığını gösterir'
---

# Erişilebilirlik

Dinamik yazı boyutu ve hareket azaltma tercihinin ortam tetiğiyle, ebeveynin verdiği etiket metninin ebeveyn tetiğiyle yeniden hesaplamaya yol açtığının ölçümü.

Önceki derste silinen öğenin liste görünümünü gözlem tetiğiyle yeniden hesaplattığını gördük. Bu derste değişiklik uygulamanın içinden gelmez; kullanıcının sistem ayarlarından gelir. Soru yine aynıdır: **bu yeniden hesaplamayı ne tetikledi?** Bu derste bakılan tetik **ortam**.

Erişilebilirlik, arayüzün farklı ihtiyaçları olan kullanıcılar tarafından kullanılabilmesidir. Çerçeve bu bilgiyi üç yoldan taşır. Birincisi etiket: bir görünümün yardımcı teknolojiye ne diye tanıtılacağını `.accessibilityLabel(_:)` söyler. İkincisi erişilebilirlik özelliği (trait): bir görünümün düğme, başlık ya da görsel gibi hangi rolde olduğunu `.accessibilityAddTraits(_:)` bildirir. Üçüncüsü sistem tercihi: kullanıcı yazı boyutunu büyütmüş, hareketi azaltmış ya da renk şemasını değiştirmiş olabilir ve bu tercihler ortam değeri olarak görünümlere ulaşır. Dinamik yazı boyutu `@Environment(\.dynamicTypeSize)` ile, hareket azaltma tercihi `@Environment(\.accessibilityReduceMotion)` ile okunur. İlk iki yol görünümün kendi bildirimidir; üçüncüsü ise görünümün dışından gelen bir değerdir. Tetik açısından asıl fark da buradadır.

Ölçüm çekirdek dosyayla yapılır; çekirdek her derste aynı dosya adıyla ve aynı içerikle gelir.

```swift
// Invalidation.swift — bir degisikligin hangi gorunumu hangi kaynak yoluyla yeniden hesaplattigini siniflandirir
enum Storage {
    case state(owner: String)
    case model(object: String)
    case environment
}

struct ViewNode {
    let name: String
    let parent: String?
    let reads: Set<String>

    init(_ name: String, parent: String?, reads: Set<String>) {
        self.name = name
        self.parent = parent
        self.reads = reads
    }
}

struct Recompute {
    let view: String
    let cause: String
}

struct ViewTree {
    let nodes: [ViewNode]
    let storage: [String: Storage]

    func ancestors(of name: String) -> [String] {
        var found: [String] = []
        var current = nodes.first { $0.name == name }?.parent
        while let next = current {
            found.append(next)
            current = nodes.first { $0.name == next }?.parent
        }
        return found
    }

    func cause(of node: ViewNode, key: String) -> String {
        guard let kind = storage[key] else { return "olcum-disi" }
        switch kind {
        case .environment:
            return "ortam"
        case .model:
            return "gozlem"
        case .state(let owner):
            if owner == node.name { return "yerel" }
            if ancestors(of: node.name).contains(owner) { return "ebeveyn" }
            return "kural-disi"
        }
    }

    func change(_ label: String, key: String) -> [Recompute] {
        let hits = nodes.filter { $0.reads.contains(key) }
            .map { Recompute(view: $0.name, cause: cause(of: $0, key: key)) }
        let skipped = nodes.filter { !$0.reads.contains(key) }.map(\.name)
        let recomputed = hits.isEmpty ? "yok" : hits.map { "\($0.view) \($0.cause)" }.joined(separator: ", ")
        let rest = skipped.isEmpty ? "yok" : skipped.joined(separator: ",")
        print("\(label): \(key) degisti | yeniden \(recomputed) | atlanan \(rest)")
        return hits
    }
}

func countCauses(_ recomputes: [Recompute]) {
    for cause in ["yerel", "ebeveyn", "gozlem", "ortam"] {
        print("\(cause): \(recomputes.filter { $0.cause == cause }.count)")
    }
}
```

## Üç Yol, Üç Okuma

Aşağıdaki parçada bir makale ekranı vardır. Başlık, yazı boyutunu okur. Özet kartı, ekranın verdiği bir metni etiket olarak kullanır ve hareket azaltma tercihine göre açılışını animasyonlu ya da animasyonsuz yapar. Kapatma düğmesinin etiketi ise sabit bir dizedir.

```swift
import SwiftUI

struct ArticleScreen: View {
    @State private var summary = "Özet"

    var body: some View {
        VStack {
            ArticleHeader()
            SummaryCard(label: summary)
            CloseButton()
        }
    }
}

struct ArticleHeader: View {
    @Environment(\.dynamicTypeSize) private var typeSize

    var body: some View {
        Text("Makale")
            .font(typeSize.isAccessibilitySize ? .title : .headline)
            .accessibilityAddTraits(.isHeader)
    }
}

struct SummaryCard: View {
    let label: String
    @Environment(\.accessibilityReduceMotion) private var reduceMotion
    @State private var isOpen = false

    var body: some View {
        Text("Özet")
            .accessibilityLabel(label)
            .onTapGesture {
                if reduceMotion {
                    isOpen.toggle()
                } else {
                    withAnimation {
                        isOpen.toggle()
                    }
                }
            }
    }
}

struct CloseButton: View {
    var body: some View {
        Button("Kapat") {}
            .accessibilityLabel("Makaleyi kapat")
    }
}
```

Bu parça derlenmez ve çıktı vermez; yalnız kaynak olarak durur. Okuma düzeni şöyledir. `ArticleScreen`, `summary`'nin sahibidir ve gövdesinde onu kartın etiketine iletir; yani değeri okur. `ArticleHeader`, `dynamicTypeSize` ortam değerini okur. `SummaryCard`, `summary`'yi etiket parametresi olarak ve `accessibilityReduceMotion` ortam değerini kapanışında okur. `CloseButton` hiçbir değer okumaz: etiketi bir dize sabitidir. Model, çerçevenin bağımlılık izleme kuralını kurar; çerçevenin kendisi değildir.

Üç değişiklik yazalım: kullanıcı yazı boyutunu büyütüyor, hareket azaltma tercihini açıyor ve ekranın özet metni değişiyor. Ortam değerini değiştirmek bu derste bir değiştirici değil, sistem ayarıdır.

```swift
// main.swift — yazi boyutu, hareket azaltma ve etiket metni
let storage: [String: Storage] = [
    "summary": .state(owner: "ArticleScreen"),
    "dynamicTypeSize": .environment,
    "accessibilityReduceMotion": .environment,
]

let screen = ViewTree(nodes: [
    ViewNode("ArticleScreen", parent: nil, reads: ["summary"]),
    ViewNode("ArticleHeader", parent: "ArticleScreen", reads: ["dynamicTypeSize"]),
    ViewNode("SummaryCard", parent: "ArticleScreen", reads: ["summary", "accessibilityReduceMotion"]),
    ViewNode("CloseButton", parent: "ArticleScreen", reads: []),
], storage: storage)

let recomputes = [
    screen.change("yazi-buyudu", key: "dynamicTypeSize"),
    screen.change("hareket-azaltildi", key: "accessibilityReduceMotion"),
    screen.change("ozet-degisti", key: "summary"),
].flatMap { $0 }

countCauses(recomputes)
```

```
yazi-buyudu: dynamicTypeSize degisti | yeniden ArticleHeader ortam | atlanan ArticleScreen,SummaryCard,CloseButton
hareket-azaltildi: accessibilityReduceMotion degisti | yeniden SummaryCard ortam | atlanan ArticleScreen,ArticleHeader,CloseButton
ozet-degisti: summary degisti | yeniden ArticleScreen yerel, SummaryCard ebeveyn | atlanan ArticleHeader,CloseButton
yerel: 1
ebeveyn: 1
gozlem: 0
ortam: 2
```

Yazı boyutu değişince yalnız başlık yeniden hesaplanır ve tetik ortamdır: değer ne başlığın ne de ebeveynin durumudur, sistemin sağladığı bir ortam değeridir. Hareket azaltma tercihi aynı biçimde yalnız kartı yeniden hesaplatır. Üçüncü satırda etiket metni değişir: sahibi olan ekran yerel tetikle, metni parametre olarak okuyan kart ebeveyn tetikle yeniden hesaplanır. Kartın ortam değerini de okuması bu satırı etkilemez, çünkü tetiği değişen anahtar belirler.

Ortam tetiğinin bir özelliği, değişikliği hiçbir görünümün yapmamasıdır. Yazı boyutu için bir atama, bir bağlama ya da bir geri çağrı yoktur; değer, görünümün dışında değişir ve onu okuyan görünüm yeniden hesaplanır. Bu yüzden ortam değerini okumak bir bağımlılık bildirimidir: görünümün gövdesi o değere bağlanmış olur.

Ortam değerinin ölçüsü ders boyunca aynı kalır: değeri kim okuyorsa yalnız o yeniden hesaplanır. Ama erişilebilirlik bağlamında bu kuralın bir sonucu daha vardır. Yazı boyutu gibi geniş etkili bir değeri ağacın tepesindeki bir görünüm okursa, o görünümün altındaki her şey etkilenmez; yalnız okuyan görünüm yeniden hesaplanır. Altındakilerin yeniden hesaplanması ancak onların da aynı değeri okumasıyla ya da ebeveynden değişen bir parametre almasıyla olur. Yani bu modelde erişilebilirlik desteği eklemek, ekranın tamamını yeniden hesaplanır hâle getirmez; çerçevenin metni kendi içinde nasıl ölçeklediği ölçülmedi. Bu kuralın görünüm sayısı arttıkça nasıl ölçeklendiği bu derste ölçülmedi.

**EK13.** Bu ölçüm yalnız `ArticleHeader`'ın `dynamicTypeSize`'ı, `SummaryCard`'ın `accessibilityReduceMotion`'ı okuduğu ağaç için geçerlidir. Her iki değeri de okuyan tek bir görünüm ölçülmedi.

**EK14.** Bu ölçüm yazı boyutunun hangi kademelere ayrıldığını, başlığın ekranda ne kadar yer kapladığını ya da satır sayısını söylemez. Bu üç şey ölçülmedi.

## Etiket Neyi Okur

Etiketin ne okuduğu, onu nasıl yazdığınıza bağlıdır. Kartın etiketi ekranın durumundan geldi; ekran metni değiştirince kart yeniden hesaplandı. Kapatma düğmesinin etiketi ise bir sabittir ve hiçbir değere bağlı değildir. Sabit etiketin yardımcı teknolojide düzgün okunması önemlidir, ama etiket hiçbir ortam ya da durum değerini okumadığı için yeniden hesaplamayı da tetiklemez.

Bu ayrım, erişilebilirliği ek iş saymaktan alıkoyar. Etiketler ve özellikler çoğunlukla sabit ya da modelden gelen metinlerdir ve ölçüm bunların ek bir yeniden hesaplama getirmediğini gösterir: yalnız etiketin değeri bir durumdan geliyorsa, o durum değişince görünüm yeniden hesaplanır. Sistem tercihleri ise ayrıdır. Bir ekranın yazı boyutuna ya da hareket tercihine tepki vermesi, o ortam değerini okuyan görünümlerle sınırlıdır ve geri kalan görünümler etkilenmez.

**EK15.** Bu ölçüm etiketi dize olarak veren bir kalıba dayanır. Etiketin yerelleştirilmiş bir anahtardan geldiği durum bir sonraki dersin konusudur ve burada ölçülmedi.

**EK16.** Bu ölçüm yardımcı teknolojinin etiketi nasıl okuduğunu, sırayı ya da özelliklerin okunuşunu kapsamaz. Bunlar ölçülmedi.

## Sınırlayıcı Ölçüm

Sabit dizeyle verilen etiketin hiçbir değer okumadığını ayrı bir blokta gösterelim. Ağaçta yalnız başlık ve kapatma düğmesi vardır. Yazı boyutu değişir; bu değeri başlık okur, düğme okumaz. Ardından hareket azaltma tercihi değişir; bu ağaçta onu okuyan yoktur.

```swift
// main.swift — sabit etiket hicbir degeri okumaz
let storage: [String: Storage] = [
    "dynamicTypeSize": .environment,
    "accessibilityReduceMotion": .environment,
]

let screen = ViewTree(nodes: [
    ViewNode("ArticleHeader", parent: nil, reads: ["dynamicTypeSize"]),
    ViewNode("CloseButton", parent: nil, reads: []),
], storage: storage)

let recomputes = [
    screen.change("yazi-buyudu", key: "dynamicTypeSize"),
    screen.change("hareket-azaltildi", key: "accessibilityReduceMotion"),
].flatMap { $0 }

print(recomputes.count)
```

```
yazi-buyudu: dynamicTypeSize degisti | yeniden ArticleHeader ortam | atlanan CloseButton
hareket-azaltildi: accessibilityReduceMotion degisti | yeniden yok | atlanan ArticleHeader,CloseButton
1
```

Kapatma düğmesi iki satırda da `atlanan` listesindedir: etiketi sabit olduğu için ne yazı boyutuna ne de başka bir ortam değerine bağlıdır. İkinci satırda okuyan görünüm olmadığı için yeniden hesaplanan listesi `yok` yazar. Sondaki `1`, iki değişiklikten yalnız birinin bir yeniden hesaplama ürettiğini gösterir. Bu, sistem tercihinin değişmesinin her zaman bir görünümü etkilemediğini gösterir. Düğmenin yazı boyutuna göre nasıl büyüdüğü, çerçevenin metni ölçeklemesi ve düzenin buna nasıl uyum sağladığı ölçülmedi; model yalnız hangi görünümün değeri okuduğunu sayar.

## Özet

- Erişilebilirlik bilgisi etiket, özellik ve sistem tercihi olarak üç yoldan taşınır.
- Dinamik yazı boyutu ve hareket azaltma tercihi ortam değerleridir; yalnız onları okuyan görünüm ortam tetiğiyle yeniden hesaplanır.
- Etiket ekranın durumundan geliyorsa, o durum değişince okuyan görünüm ebeveyn tetikle yeniden hesaplanır.
- Sabit dizeyle verilen etiket hiçbir değer okumaz ve yeniden hesaplamaya yol açmaz.
- Bu dersin tetiği: **ortam**.

## Sonraki Adım

Sistem tercihlerinden biri henüz ele alınmadı: kullanıcının dili ve bölgesi. Sonraki derste yerel ayarın ve yazı yönünün ortam değeri olarak hangi görünümleri yeniden hesaplattığını, tarih biçimleyen bir modelin özelliğinin ise hangi kanaldan geldiğini ölçeceğiz.
