sheet(item:onDismiss:content:) yöntemini tek bir isteğe bağlı seçili öğeyle kullanın ve sheet’i, closure’ının aldığı öğeden oluşturun. Böylece bir Mac uygulamasında hem sheet’in açılıp açılmayacağını hem de ne göstereceğini tek bir değer belirler.

Bu eğitim, küçük bir masaüstü görevini uygular: yerel bir örnek öğeye tıklayıp ayrıntılarını hemen inceleyin. Ayrıca boş açılan, önceki seçimi gösteren veya bir AppKit görünümünde eski metni görüntüleyen bir sheet için tanılama adımları sunar.

Öğe tabanlı bir sheet’i neden kullanmalı?

SwiftUI, sunum için iki ilgili yöntem sunar. Boolean overload, binding’i true olduğunda sunum yapar. Öğe overload’ı, isteğe bağlı ve tanımlanabilir bir değer kabul eder ve bu değeri içerik closure’ına sağlar. Sabit bir panel için Boolean biçimini; panelin içeriği bir seçime bağlıysa öğe biçimini seçin. Apple’ın Boolean tabanlı sheet’ler ve öğe tabanlı sheet’ler belgelerine bakın.

Seçim ve sunum için ayrı özellikler kullanan bir tasarım, seçim olmadan sunum istenmesi gibi durumlara izin verir. Bunları tek bir isteğe bağlı değerde birleştirmek, bu olasılığı kendi durum modelinizden çıkarır: nil seçili bir öğe olmadığını, dolu bir değer ise incelenecek öğeyi ifade eder. Bu, belgelenmemiş bir SwiftUI zamanlama kusuruna ilişkin bir iddia değil, iki API’den çıkarılan bir tasarım sonucudur.

Mevcut bir uygulama seçimi atayıp sonra bir Boolean’ı değiştiriyorsa, yalnızca bu iki ifade ilk sunumun neden başarısız olduğunu açıklamaz. Belirtiyi zamanlamaya bağlamadan önce içeriğin veri yolunu inceleyin. Sorulması gereken, sheet’in kendisine sağlanan girdiyi mi görüntülediği, başka bir özelliği mi okuduğu, yoksa ayrı kaydedilmiş bir kopyayı mı gösterdiğidir.

Eksiksiz bir macOS örneği oluşturun

SwiftUI arayüzünü kullanan bir macOS uygulama projesini Xcode’da oluşturun. Bu örnek için dağıtım hedefini macOS 12 veya üzeri olarak ayarlayın. Öğe tabanlı sheet API’si macOS 10.15’ten beri kullanılabilirken aşağıda kullanılan ortam kapatma eylemi macOS 12 gerektirir. Apple bu kullanılabilirlik sınırlarını öğe tabanlı sheet’ler ve dismiss ortam değeri için belgelemiştir.

Oluşturulan uygulama bildirimini ve içerik görünümünü bu eksiksiz programla değiştirin. Hedefte yalnızca bir uygulama giriş noktası bulunsun. Aşağıdaki tüm etiketler ve açıklamalar sentetik yerel örnek verilerdir.

import SwiftUI

struct SampleItem: Identifiable {
    let id: String
    let title: String
    let detail: String
}

@main
struct FirstSheetDemoApp: App {
    var body: some Scene {
        WindowGroup {
            ItemListView()
        }
    }
}

struct ItemListView: View {
    private let items = [
        SampleItem(
            id: "tile-a",
            title: "Amber Tile",
            detail: "A square sample with an amber finish."
        ),
        SampleItem(
            id: "tile-b",
            title: "Blue Tile",
            detail: "A rectangular sample with a blue finish."
        )
    ]

    @State private var presentedItem: SampleItem? = nil

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Sample Items")
                .font(.title2)

            ForEach(items) { item in
                Button("Inspect \(item.title)") {
                    presentedItem = item
                }
            }
        }
        .padding(24)
        .frame(minWidth: 360, minHeight: 200)
        .sheet(item: $presentedItem) { item in
            ItemDetailView(item: item)
        }
    }
}

struct ItemDetailView: View {
    let item: SampleItem
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text(item.title)
                .font(.title)

            Text(item.detail)

            Text("Item ID: \(item.id)")
                .font(.caption)

            HStack {
                Spacer()
                Button("Done") {
                    dismiss()
                }
            }
        }
        .padding(24)
        .frame(width: 380, height: 220)
    }
}

Düğme, tıklanan değeri presentedItem değişkenine atar. Ardından sunum closure’ı, kendi item parametresini ItemDetailView’a aktarır. Ayrıntı görünümünde ikinci bir seçili öğe durum özelliği yerine let item adlı sıradan bir girdi özelliği olduğuna dikkat edin. Apple, tek bir doğruluk kaynağının korunmasını ve salt okunur değerlerin özellikler aracılığıyla paylaşılmasını, alt görünümün yazma erişimine ihtiyaç duyduğu durumlarda ise binding kullanılmasını önerir. State belgesine bakın.

Kapatma eylemi, sheet’in ortamını okuduğu ItemDetailView içinde yer almalıdır. Apple, bu eylemi sunan görünümde okuyup sheet içeriğinden çağırmanın, sunan görünümün ortamını kullandığı konusunda özellikle uyarır. Bildirimi, gösterildiği gibi sheet’in kendi içeriğinin yanına koyun. dismiss belgesine bakın.

Program, girdilerin ve başvuruların tutarlı olması açısından incelendi; bu ortamda Swift araç zinciri bulunmadığından derlenmedi veya çalıştırılmadı. Aşağıdaki kontrolleri hedef macOS sürümünüzde Xcode’da gerçekleştirin.

Bilinçli bir tıklama sırasıyla ilk sunumu doğrulayın

Her ilk sunum kontrolüne uygulamayı yeniden başlatarak başlayın. Yalnızca başka bir öğeyi açtıktan sonra test etmek, ilk belirtiyi gizleyebilir. Aşağıdaki beklentiler, örnekteki açık etiketlerden ve veri atamalarından çıkarılmıştır; bildirilmiş test sonuçları değil, kabul ölçütleridir.

Eylem Sheet’te beklenen içerik Kontrol ettiği durum
Uygulamayı başlatıp önce Inspect Blue Tile öğesine tıklayın Blue Tile, dikdörtgen açıklaması ve tile-b İlk sunumda tıklanan öğe kullanılır
Done düğmesine tıklayıp Amber Tile öğesini inceleyin Amber Tile, kare açıklaması ve tile-a Sonraki seçim içeriğe ulaşır
Kapatıp Amber Tile öğesini tekrar inceleyin Aynı amber ayrıntıları Bir öğeyi yeniden açmak tutarlı kalır
Uygulamayı yeniden başlatıp önce Amber Tile öğesini inceleyin Amber ayrıntıları hemen görüntülenir Doğruluk, önce hangi örneğin açıldığına bağlı değildir

Hem başlığı hem de kimliği göstermek, bu kontrolü yalnızca başlığı kontrol etmekten daha yararlı kılar. Gerçek arayüzünüzde aynı görünen ada sahip birden fazla öğe bulunabiliyorsa geliştirme sırasında aynı başlıklı, farklı kimlik ve açıklamalara sahip iki sentetik öğe kullanın. Bu, görünen metne göre yanlışlıkla seçim yapılmasını ortaya çıkarır.

Eski içeriği düğmeden son görünüme kadar tanılayın

Bu kontrolleri sırayla uygulayın. Her adım uyuşmazlığın yerini daraltır; böylece ilgisiz sunum geçici çözümleri eklemeden sorumlu katmanı değiştirebilirsiniz.

  1. Eylemin girdisini kontrol edin. Tıklanan düğmenin eylemine bir kesme noktası koyup item.id değerini inceleyin. Eylemin amaçlanan kaydı aldığını doğrulayın.
  2. Sunum girdisini kontrol edin. Sheet closure’ının içindeki item parametresini inceleyin. Ayrı bir seçimi yeniden aramak yerine bu parametreyi ayrıntı görünümüne aktarın.
  3. Son görüntülenen özelliği kontrol edin. Başlık ve açıklamanın ayrıntı görünümünün girdisinden okunduğunu doğrulayın. Önceki bir değeri içeren önbelleğe alınmış bir özellik veya yerel taslak arayın.
  4. AppKit köprüsünü kontrol edin. SwiftUI metni doğru, ancak sarmalanmış metin eskiyse representable’ın güncelleme yöntemini inceleyin.

Kimliği kararlı tutun

Öğe tabanlı API, Identifiable protokolünü gerektirir. Swift bu protokolü kararlı kimlik etrafında tanımlar; bu kimliğin süresini ve kapsamını ise uyum sağlayan türe ve onu kullanan yapıya bırakır. Örnek, iki kaydı birbirinden ayıran saklanmış string kimlikler kullanır. Identifiable belgesine bakın.

Gerçek bir listede, arayüzünüzün desteklediği güncellemeler boyunca aynı kaydı tanımlamayı sürdüren bir kimlik seçin. Değişebilen veya birden çok öğe tarafından paylaşılabilen bir başlığı kimlik olarak kullanmaktan kaçının. Ayrıca her okunduğunda yeni bir UUID oluşturan hesaplanmış bir id kullanmaktan kaçının; bu, kararlı kimlik sağlamaz.

Görüntüleme girdisini düzenlenebilir bir taslaktan ayırın

Bir denetleyici item.title değerini doğrudan görüntüleyebilir. Bir düzenleyici bilinçli olarak yerel bir taslak oluşturabilir, ancak taslak eklendiğinde yaşam süresi tanımlanması gereken başka bir değer ortaya çıkar. Taslağın ne zaman oluşturulacağına, sonraki model değişikliklerinin onun yerini alıp almayacağına ve kullanıcı bitirdiğinde veya iptal ettiğinde ne olacağına karar verin.

Apple, SwiftUI’nin görünüm kimliği için durum depolamasını koruduğunu ve bu depolamayı kimliğin yaşam süresinin başında başlattığını açıklar. Bir görünüm değerini yeniden oluşturmak, kendi başına yeni bir durum oluşturmaz. Dolayısıyla girdiden yerel durum başlatmak, bu durumu sonraki girdilerle eşzamanlı tutmanın genel bir yöntemi değildir. Demystify SwiftUI belgesine bakın.

Bu salt okunur görev için sıradan girdi özelliğini kullanın. Düzenleme özelliği ekleyecekseniz açık bir taslak ve kaydetme tasarımı ya da amaçlanan model değerine yönelik bir binding seçin. Metni yenilemek için görünüm kimliğini değiştirmekten kaçının: kimliği değiştirmek ilişkili durumu yenisiyle değiştirir ve tamamlanmamış bir taslağı silebilir. Bu sonuç, Apple’ın belgelenmiş durum yaşam süresi modelinden çıkar.

Sheet bir AppKit metin görünümü içerdiğinde neler değişir?

Bir NSTextView içeren sheet yine aynı seçili öğe veri yoluna ihtiyaç duyar. Ayrıca köprünün doğru uygulanması gerekir. Apple’ın NSViewRepresentable protokolü, ilk oluşturmayı makeNSView(context:) içinde, sonraki yapılandırmaları ise updateNSView(_:context:) içinde ele alır. Metni yalnızca oluşturma sırasında atayan bir sarmalayıcıda sonraki metin girdilerini uygulayacak bir yöntem yoktur. NSViewRepresentable belgesine bakın.

Salt okunur bir sarmalayıcıda yerel görünümü sağlanan metinle başlatın ve gerektiğinde görüntülenen metni güncel girdiyle eşleştirin. Apple, ilgili AppKit görünümünü etkileyen değişikliklerde SwiftUI’nin güncelleme yöntemini çağırdığını belgeler. updateNSView(_:context:) belgesine bakın.

Düzenlenebilir bir sarmalayıcı ek bir politika gerektirir: devam eden düzenlemelerin üzerine yazacak şekilde her güncellemede metni gelişigüzel değiştirmeyin. Apple’ın representable belgelerinde açıkladığı gibi, yerel temsilci veya target-action değişikliklerini SwiftUI’ye iletmek için bir coordinator kullanın. Temsil edilen görünümün çerçevesini ve sınırlarını SwiftUI’nin kontrol etmesine izin verin; Apple bu yerleşim özelliklerini doğrudan ayarlamamanız konusunda uyarır.

TextKit; metin depolama, yerleşim ve görüntülemeyi ele alır. Apple, NSTextView tarafından sunulan hem modern NSTextLayoutManager yolunu hem de eski NSLayoutManager yolunu belgeler. Bu olanaklar sheet’in seçili kaydını sağlamaz. Metin yerleşimini araştırmadan önce köprünün doğru öğe metnini aldığını doğrulayın ve ek TextKit API’lerini kullanıma sokmadan önce kullanılabilirliği ayrıca kontrol edin. TextKit belgesine bakın.

Görevle eşleşen sunum modelini seçin

İçerik sabitse ve değişen tek girdi görünürlükse Boolean overload’ı kullanın. Bu denetleyici görevi için öğe overload’ını kullanın. Apple, sağlanan öğenin değiştirilmesinin mevcut sheet’i kapatıp yenisini açabileceğini belgeliyor; bu nedenle öğe değişimini aynı sunum içinde kesintisiz düzenleme sözü olarak değerlendirmeyin. sheet(item:onDismiss:content:) belgesine bakın.

Doğru ilk sunum için seçili kaydın izini sürmeyi kolaylaştırın: düğme eyleminde tek bir atama, sheet closure’ında tek bir öğe parametresi ve ayrıntı görünümünde tek bir girdi. Her iki örnek öğeyi de uygulamayı yeniden başlattıktan sonra doğrulayın. Sonuç hâlâ farklıysa tanılama adımları uyuşmazlığın seçim, korunan durum veya yerel görünüm güncelleme yolundan hangisiyle geldiğini gösterir.

Kaynaklar