Alan değerini uygulamadan bir öneri eklemek için tamamlamayı ve göndermeyi ayrı tutun. macOS 15 veya sonraki sürümlerde SwiftUI yerel metin önerileri sunar; üst öğelerin gönderim işleyicilerini engellemek için submitScope() kullanın ve son işlem için açık bir düğme ekleyin.

Bu eğitim, kendi Mac uygulamanızda küçük bir etiket seçici oluşturur. Bl yazıldığında Blue Tile gibi yapay etiketler sunulur. Bir öneri seçildiğinde düzenlenebilir taslak güncellenir; Apply Label düğmesine tıklandığında bu taslak uygulanmış değere kopyalanır. Bu ayrım önemlidir: uygulama eylemini önlemek ile Return tuşu komutunu işlemek farklı gereksinimlerdir.

Etkileşime uygun API’yi seçin

Apple’ın textInputSuggestions(_:) değiştiricisi, metin alanı için seçenekler sunar. Eyleme dönüştürülebilen her öneri, yerine konacak metni sağlayan textInputCompletion(_:) gerektirir. Her iki API de macOS 15 ve sonraki sürümler için belgelenmiştir. Tamamlama değiştiricisi olmayan bir öneri görünebilir ancak tıklamalara yanıt vermez. Apple: textInputSuggestions(_:), Apple: textInputCompletion(_:)

Kısa bir etiket alanında taslağın tamamını değiştirmek uygundur. Apple’ın öneriler belgeleri, alanın tamamının bu şekilde değiştirildiğini açıklar. Bu API’nin imleç konumuna göre çalışan bir belirteç düzenleyicisi veya satır içi son ek önizlemesi sunduğunu varsaymayın; bunlar daha özel bir düzenleme tasarımı gerektirir. Apple: textInputSuggestions(_:)

Gereksiniminiz Uygun başlangıç noktası
macOS 15 veya sonraki sürümlerde tam etiketler sunmak SwiftUI yerel metin önerileri
Alanın üst öğeye ait bir gönderim işleyicisini çağırmasını önlemek Alanda submitScope()
Özel bir öneri düzeni kullanmak veya daha eski bir dağıtım hedefini desteklemek Taslak bağlamasını güncelleyen uygulamaya ait öneri düğmeleri
Return tuşuyla vurgulanan öğeyi kabul edip bu komutu işlemek Komut işleme özelliğine sahip, uygulamanın yönettiği bir AppKit denetimi
Bir son eki önizlemek veya ekleme noktasındaki sözcüğü değiştirmek Açık bir tamamlama aralığıyla AppKit metin tamamlama

Son iki satır, belgelenmiş komut ve tamamlama API’lerinden çıkarılan mimari tercihlerdir. Etkileşim, değiştirme metni ve gönderim sınırının sağladığından daha fazla denetim gerektirdiğinde bunlar yararlıdır.

Eksiksiz bir SwiftUI etiket seçici oluşturun

Xcode’da SwiftUI kullanan ve macOS 15 API’lerini içeren bir SDK’yla bir macOS App projesi oluşturun. Dağıtım hedefini macOS 15 veya sonraki bir sürüm olarak ayarlayın. Oluşturulan uygulama ve içerik görünümü bildirimlerini aşağıdaki tek kaynak dosyayla değiştirin ve hedefte yalnızca bir @main uygulama bildirimi bırakın.

Örnek, draft ve appliedLabel değerlerini ayrı tutar. Yerel eşleştirme kuralı özellikle basittir: büyük/küçük harfe duyarlı önek eşleştirmesi, boş metinde öneri sunmama ve tam eşleşme için öneri göstermeme. Swift, hasPrefix(_:) işlevini dize öneki karşılaştırması olarak belgeler; daha kapsamlı eşleştirme kuralları uygulama tercihidir. Swift: Strings and Characters

import SwiftUI

@main
struct LabelCompletionApp: App {
    var body: some Scene {
        WindowGroup {
            LabelCompletionView()
        }
    }
}

struct LabelCompletionView: View {
    private let labels = [
        "Blue Tile",
        "Blue Tray",
        "Green Tile",
        "Round Tray"
    ]

    @State private var draft = ""
    @State private var appliedLabel = ""
    @State private var applyCount = 0
    @FocusState private var fieldIsFocused: Bool

    private var matches: [String] {
        guard !draft.isEmpty else { return [] }
        return labels.filter {
            $0.hasPrefix(draft) && $0 != draft
        }
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Choose a label")
                .font(.headline)

            TextField("Type Bl to see suggestions", text: $draft)
                .textFieldStyle(.roundedBorder)
                .focused($fieldIsFocused)
                .textInputSuggestions {
                    ForEach(matches, id: \.self) { label in
                        Text(label)
                            .textInputCompletion(label)
                    }
                }
                .submitScope()

            Button("Apply Label") {
                appliedLabel = draft
                applyCount += 1
            }
            .disabled(draft.isEmpty)

            Text("Draft: \(draft)")
            Text("Applied: \(appliedLabel)")
            Text("Apply count: \(applyCount)")
        }
        .padding(24)
        .frame(width: 420)
        .onAppear {
            fieldIsFocused = true
        }
    }
}

Bu, örnek etiketleri ve durumu da içeren eksiksiz bir uygulama örneğidir. Alınan API belgelerine göre incelendi ancak burada derlenip çalıştırılmadı; çünkü Swift araç zinciri ve macOS arayüz çalışma zamanı mevcut değildi.

Öneri seçmek etiketi neden uygulamaz?

Her tamamlama, metin alanı için bir dize sağlar; alanın bağlaması draft değerine bağlıdır. appliedLabel ataması yapan veya applyCount değerini artıran tek kod, Apply Label düğmesinin eylemidir. Bu nedenle taslağın güncellenmesi, bu örnekte son eylemi tetikleyemez.

Alanın ayrıca submitScope() değiştiricisi vardır. Apple, bu değiştiricinin gönderim tetikleyicilerinin görünüm hiyerarşisindeki daha üst gönderim değiştiricilerine ulaşmasını önlediğini belgeler. Bileşen daha sonra üst öğesinde onSubmit bulunan daha büyük bir forma yerleştirildiğinde bu önemlidir. Apple: submitScope(_:)

İlk odak @FocusState ile belirlenir. Apple, bağlı değerin programatik olarak atanmasının odağı ilişkili görünüme taşıdığını belgeler. Burada odak, düzenlemeyi kolaylaştırır; etiketin uygulanıp uygulanmayacağını kontrol etmez. Apple: FocusState

Örneğin bilerek izin verdiği durumlar

Etiket listesi, geçerli girdileri kısıtlamak yerine öneriler sunar. Square Tile yazmak yine de Apply Label düğmesini etkinleştirir. Arayüzünüz yalnızca listelenen etiketlere izin veriyorsa doğrulama kuralını açıkça değiştirin; örneğin düğmeyi yalnızca taslak katalogdaki bir girdiye eşitse etkinleştirin. Eşleşmeyen bir taslağı sessizce ilk öneriyle değiştirmeyin.

Örnek ayrıca etiketin tamamını değiştirir. Taslak birden çok sözcük içeriyorsa tamamlama seçmek, alanın tamamlanmış değerini seçmek anlamına gelir. Çevresindeki metni koruması gereken bir belirteç düzenleyicisi, seçimi dikkate alan bir değiştirme yöntemi gerektirir.

“Göndermeden” ifadesinin ne anlama geldiğini anlayın

SwiftUI’ın onSubmit(of:_:) belgeleri, kullanıcı Return tuşuna bastığında metin alanının gönderim eylemini tetiklediğini belirtir. Gönderim eylemleri tek bir görünüme veya daha büyük bir hiyerarşiye eklenebilir. Otomatik tamamlama seçiminin beklenmedik bir uygulama eylemini tetiklediği durumlarda her iki konumu da inceleyin. Apple: onSubmit(of:_:)

submitScope(), üst öğe işleyicileri için bir sınır oluşturur. İçeride hiçbir gönderim olayının oluşmayacağını, düzenlemenin etkin kalacağını veya her klavye komutunun işleneceğini garanti ettiği belgelenmemiştir. Benzer şekilde, Apple’ın tamamlama değiştiricileri metin değiştirmeyi belgeler; Return tuşu davranışının her durumda bastırılmasını değil. Etkileşimi seçerken bu sınırları göz önünde bulundurun. Apple: submitScope(_:), Apple: textInputCompletion(_:)

Mevcut bir bileşen için şu yolları ayrı ayrı inceleyin:

  1. Return tuşu değeri hiçbir zaman uygulamamalıysa alanın kendi onSubmit içindeki son uygulama eylemini kaldırın.
  2. Üst öğenin gönderim eylemini engellemek için alana submitScope() ekleyin.
  3. Düğme klavye kısayollarını, özellikle açık bir varsayılan eylemi, ayrıca kontrol edin.
  4. Taslak değiştiğinde son eylemi gerçekleştiren değişiklik gözlemcilerini veya model ayarlayıcılarını kontrol edin.

Boş bir yerel onSubmit kapanışı, gönderim sınırının belgelenmiş bir alternatifi değildir. Apple, yayılımı durdurmak için özellikle submitScope() sağlar. Uygulama yalnızca etkin bir tamamlama yokken Return tuşuyla gönderim yapacaksa, bu koşullu klavye politikası ek durum ve komut işleme gerektirir. Apple: onSubmit(of:_:)

Return tuşuyla kabul edip durdurmanız gerektiğinde AppKit kullanın

Uygulamanın yönettiği bir NSTextField için AppKit, control(_:textView:doCommandBy:) sağlar. Metin görünümü bağımsız değişkeni, denetimin alan düzenleyicisidir. Temsilci, bağlı bir komutu işleyip true döndürebilir; false döndürülürse komut bu temsilci tarafından işlenmemiş kalır. Bu, metin alanındaki komutları özelleştirmek için belgelenmiş genişletme noktasıdır. Apple: control(_:textView:doCommandBy:)

Özel bir tamamlama denetleyicisi bu genişletme noktasını şu sırayla kullanabilir:

  1. Öneri listesinin açık olup olmadığını ve hangi öğenin vurgulandığını izleyin.
  2. Geçerli bir vurgulanmış öğe varken Return komutu geldiğinde bu öğeyi taslağa ekleyin.
  3. Öneri listesini kapatın ve uygulamanın taslak modelini eşitleyin.
  4. Denetleyici komutu işlediği için true döndürün.
  5. Denetleyicinin işlemediği komutlar için false döndürün.

Bu sıra, yerleşik bir otomatik tamamlama politikası değil, temsilci sözleşmesinden türetilmiş bir uygulama tasarımıdır. Liste kapalıyken Return tuşunun ne yapacağına ayrıca karar verin. Bunun yerine bağımsız bir NSTextView kullanıyorsanız karşılık gelen kanca textView(_:doCommandBy:) olur; Apple, true döndürmenin metin görünümünün komutu kendisinin gerçekleştirmesini önlediğini belirtir. Apple: textView(_:doCommandBy:)

Metin tamamlama için NSTextView.insertCompletion(_:forPartialWordRange:movement:isFinal:), değiştirme ve seçim değişikliklerini destekler. isFinal: false olduğunda önerilen son eki seçer; isFinal: true olduğunda seçimi tamamlanmış sözcüğün sonrasına taşır. Bu bayrak uygulama gönderimini değil, tamamlama durumunu belirtir. movement bağımsız değişkeni, tamamlama gezinmesinin veya seçiminin nasıl gerçekleştiğini belirtir. Apple: insertCompletion(_:forPartialWordRange:movement:isFinal:)

Doğru metin aralığını koruyun

AppKit’in rangeForUserCompletion özelliği, kısmi sözcüğün başlangıcından ekleme noktasına kadar olan bölümünü belirler. Amaçlanan değiştirme işlemine uygun bir aralık kullanın ve düzenlemelerden ya da imleç hareketinden sonra bu aralığı yeniden hesaplayın. Metin değiştikten sonra önceden yakalanmış bir aralığı düşünmeden yeniden kullanmayın. Apple: rangeForUserCompletion

Metin aralıkları arasında köprü kurarken Swift’in karakter sayısını NSString uzunluğunun yerine kullanmayın. Swift belgeleri, String türünün genişletilmiş grafem kümelerini saydığını, NSString uzunluğunun ise UTF-16 kod birimlerini saydığını açıklar. Bu değerler farklı olabilir. SwiftUI örneğinde alanın tamamını bağlamayla değiştirmek bu aralık dönüşümünü tümüyle önler. Swift: Strings and Characters)

Ekleme ve uygulama işlemlerini ayrı ayrı doğrulayın

Sonucu desteklenen her macOS sürümünde görünür taslak, uygulanmış değer ve sayaçla kontrol edin. Aşağıdakiler örnek için beklenen kontrollerdir; bildirilmiş test sonuçları değildir.

Eylem Gözlemlenmesi beklenen sonuç
Bl yazın Taslak Bl olur; eşleşen etiketler sunulur
Blue Tile seçeneğine tıklayın Taslak Blue Tile olur; uygulanmış değer ve sayaç değişmeden kalır
Düzenleme sırasında Return tuşuna basın Uygulama taslağı uygulamaz
Apply Label düğmesine tıklayın Uygulanmış değer taslağa kopyalanır; sayaç bir kez artar
Taslağı sonradan düzenleyin Önceki uygulanmış değer görünür kalır
Taslağı temizleyin Öneri kalmaz ve Apply Label devre dışı kalır
bl yazın Örneğin büyük/küçük harfe duyarlı kuralı uyarınca eşleşme bulunmaz

Yerel öneri listesindeki klavye seçimini de deneyin ve alanı gerçek üst görünümüne yerleştirdikten sonra kontrolleri tekrarlayın. Apple, macOS penceresini taşımak gibi olayların yerel öneri arayüzünü kapatabileceğini belirtir; bu nedenle liste olmadan da taslak kullanılabilir kalmalıdır. Apple: textInputSuggestions(_:)

Dağıtım hedefiniz macOS 15’ten eskiyse, kullanılabilirlik koşuluna bağlı yerel bir görünüm ve yedek seçenek sunun ya da her yerde uygulamaya ait öneri düğmelerini kullanın. Yedek bir düğme etiketini doğrudan taslağa atayabilir ve son eylemi Apply Label düğmesinde bırakabilir. Böylece taslak ile uygulama aynı şekilde birbirinden ayrılır; klavye gezinmesi ve sunum ise bileşeninizin sorumluluğunda kalır.

Bu etiket seçici görevinde yararlı sınır gözlemlenebilir: bir tamamlamayı kabul etmek düzenlenebilir taslağı değiştirir ve yalnızca açık son eylem uygulanan etiketi değiştirir. Bu sınır için SwiftUI’ın yerel önerilerini ve gönderim kapsamını kullanın; Return tuşunu işlemeniz gerektiğinde AppKit komut işlemeye geçin.

Kaynaklar