← TipKit

Temeller

TipKit Dokümantasyonu

TipKit kullanarak uygulama özelliklerini keşfedilebilir hale getirmenin temelleri.


TipKit ile Uygulama Özelliklerini Vurgulama

Örnek Kod | TipKit

*iOS 18.0+, iPadOS 18.0+, Mac Catalyst 18.0+*

İpuçları kullanarak uygulamanızdaki yeni özelliklere dikkat çekin.

TipKit ile kullanıcılara uygulamanızdaki yeni bir özelliği öğretebilir veya bir görevi daha hızlı tamamlamanın yollarını gösterebilirsiniz. Bu rehber, uygulamanıza ekleyebileceğiniz farklı ipucu türlerini ve bunların nerede ve ne zaman görüneceğini kontrol etme yöntemlerini açıklar.

İpucu İçeriği Tanımlama

Tip protokolü, özelliklerin ne yaptığını açıklayan metin ve görselleri, ayrıca ipucunun ne zaman görüneceğine dair kuralları tanımlar:

struct InlineTip: Tip {
    var title: Text {
        Text("Favori Olarak Kaydet")
    }

    var message: Text? {
        Text("Favori bahçeleriniz her zaman listenin en üstünde görünür.")
    }

    var image: Image? {
        Image(systemName: "star")
    }
}

İpuçlarını Yapılandırma ve Yükleme

İpuçlarının görüntülenmesi için uygulamaya yüklenmesi gerekir. Uygulama başlangıcında configure(_:)) çağrısıyla tüm ipuçları yüklenir. En iyi uygulama, bunu uygulama oturumu başına bir kez çağırmaktır:

@main
struct TipKitExamples: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }

    init() {
        do {
            try Tips.configure()
        }
        catch {
            print("İpuçları başlatılırken hata: \(error)")
        }
    }
}

Satır İçi (Inline) İpuçları

Mümkün olduğunca bu stil kullanılmalıdır; kullanıcıların etkileşim kurmak isteyebileceği UI öğelerini kapatmaz. Satır içi ipuçları, vurguladıkları özelliği içeren görünüme doğrudan gömülür ve yerleşimi buna göre ayarlar.

struct InlineView: View {
    let inlineTip = InlineTip()

    var body: some View {
        VStack(spacing: 20) {
            // İpucuyu vurgulamak istediğiniz özelliğin yakınına yerleştirin.
            TipView(inlineTip, arrowEdge: .bottom)
            Button {
                // Kullanıcı özelliği kullandığında ipucunu geçersiz kılın.
                inlineTip.invalidate(reason: .actionPerformed)
            } label: {
                Label("Favori", systemImage: "star")
            }
        }
    }
}

Popover İpuçları

Alttaki yerleşimi değiştirmek istenmeyen durumlarda veya kullanıcının ipucunun kapattığı kontrollerle etkileşime girmesine gerek olmadığında kullanılır:

struct PopoverView: View {
    let highlightTip = HighlightTip()

    var body: some View {
        Image(systemName: "wand.and.stars")
            .imageScale(.large)
            .popoverTip(highlightTip)
            .onTapGesture {
                highlightTip.invalidate(reason: .actionPerformed)
            }
    }
}

Eylem Düğmeleri

Düğmeler, kullanıcılara yeni bir özelliği kullanıp kullanmamaya karar vermeden önce ek bilgi ve seçenekler sunar:

struct PasswordResetTip: Tip {
    var title: Text {
        Text("Yardıma İhtiyacınız Var Mı?")
    }

    var message: Text? {
        Text("Hesabınıza giriş yapmak için yardıma mı ihtiyacınız var?")
    }

    var actions: [Action] {
        Action(id: "reset-password", title: "Şifre Sıfırla")
        Action(id: "faq", title: "SSS Sayfasını Görüntüle")
    }
}

Eylem geri çağrısında action.id kontrol edilerek hangi düğmeye basıldığı belirlenir:

TipView(passwordResetTip, arrowEdge: .bottom) { action in
    if action.id == "reset-password", let url = URL(string: "https://iforgot.apple.com") {
        openURL(url)
    }
    if action.id == "faq", let url = URL(string: "https://appleid.apple.com/faq") {
        openURL(url)
    }
}

Parametre Tabanlı Kurallar

Uygulama durumunu izlemek için bir değişkeni Parameter sarmalayıcısıyla tanımlayın ve #Rule makrosuyla görüntülenme kuralı oluşturun:

struct ParameterRuleTip: Tip {
    @Parameter
    static var isLoggedIn: Bool = false

    var rules: [Rule] {
        #Rule(Self.$isLoggedIn) {
            $0 == true
        }
    }
}

Durum değişikliğini tetiklemek için:

Button("Giriş Yap") {
    ParameterRuleTip.isLoggedIn.toggle()
}

Not: İpucu yapısında herhangi bir kural tanımlanmazsa, tüm ipuçları kapatılana veya gösterim sıklığı eşiğini aşana kadar görüntülenir.

Olay Tabanlı Kurallar

Kullanıcı eylemlerini izlemek ve buna göre ipuçlarını görüntülemek için Event kullanılır:

struct EventRuleTip: Tip {
    static let didTriggerControlEvent = Event(id: "didTriggerControlEvent")

    var rules: [Rule] {
        #Rule(Self.didTriggerControlEvent) {
            $0.donations.count >= 3
        }
    }
}

İlişkili bağış değerleriyle olay oluşturma da mümkündür:

struct FoodEventTip: Tip {
    struct Item: Codable, Sendable {
        var name: String
        var isFavorite: Bool
    }

    static let viewedSpecificFood: Tips.Event<Item> = Tips.Event(id: "viewed-specific-food")

    var rules: [Rule] {
        #Rule(FoodEventTip.viewedSpecificFood) {
            $0.donations.smallestSubset(groupedBy: \.name).count > 1
        }
        #Rule(FoodEventTip.viewedSpecificFood) {
            $0.donations.donatedWithin(.hour)
                .filter({ $0.isFavorite == true }).count > 4
        }
    }
}

Kuralları Birleştirme

Parametreler, olaylar ve seçenekler birleştirilerek karmaşık koşullar oluşturulabilir. rules özelliğindeki kurallar mantıksal VE (AND) ile birleşir:

struct ComboTip: Tip {
    @Parameter
    static var isLoggedIn: Bool = false
    static let enteredView = Event(id: "enteredView")

    var rules: [Rule] {
        #Rule(Self.$isLoggedIn) { $0 == true }
        #Rule(Self.enteredView) { $0.donations.count >= 3 }
    }
}

Test İçin İpucu Kurallarını Geçersiz Kılma

Tips.showAllTipsForTesting()          // Tüm ipuçlarını göster
Tips.showTipsForTesting([tip1, tip2]) // Belirli ipuçlarını göster
Tips.hideAllTipsForTesting()          // Tüm ipuçlarını gizle
try Tips.resetDatastore()             // TipKit verilerini sıfırla

Tip Protokolü

Protokol | TipKit

*iOS 17.0+, iPadOS 17.0+, Mac Catalyst 17.0+, macOS 14.0+, tvOS 17.0+, visionOS 1.0+, watchOS 10.0+*

Bir ipucunun içeriğini ve görüntülenme koşullarını belirleyen tip.

protocol Tip : Identifiable, Sendable

İpucu İçeriği Ayarlama

| Özellik | Tip | Açıklama | | --- | --- | --- | | title | Text | İpucunu adlandıran başlık (zorunlu) | | message | Text? | Özelliğin nasıl kullanılacağının kısa açıklaması | | image | Image? | İpucuyla ilişkili görsel; başlık ve mesajın solunda görünür | | id | String | Benzersiz tanımlayıcı; varsayılan olarak tip adı kullanılır |

Özel tanımlayıcı örneği — Yeniden kullanılabilir ipuçları oluşturmak için:

struct NewTrailTip: Tip {
    let newTrail: Trail

    var id: String {
        "NewTrailTip-\(newTrail.id)"
    }
}

Görüntülenme Kontrolü

  • rules: [Self.Rule] — İpucunun görüntülenme uygunluğunu belirleyen kurallar.
  • RuleTips.Rule tip takma adı. Görüntülemeden önce karşılanması gereken koşul.
  • EventTips.Event tip takma adı. Tekrarlanabilir kullanıcı tanımlı eylem.

Davranış Özelleştirme

  • options: [any TipOption] — İpucu için özelleştirmeler.
  • OptionTipOption tip takma adı.
  • IgnoresDisplayFrequency — Önceden yapılandırılmış gösterim sıklığı aralığına uyup uymayacağını kontrol eder. Varsayılan: false.
  • MaxDisplayCount — İpucu en fazla kaç kez görüntülendikten sonra otomatik geçersiz kılınacağını belirler. Varsayılan: sınırsız.
  • MaxDisplayDuration — İpucu en fazla ne kadar süre görüntülendikten sonra geçersiz kılınacağını belirler (kümülatif). Minimum: 60 saniye. Varsayılan: sınırsız.
struct FavoriteBackyardTip: Tip {
    var options: [any Option] {
        MaxDisplayCount(3)
        MaxDisplayDuration(300.0) // 5 dakika
        IgnoresDisplayFrequency(true)
    }
}

Eylemler

@Tips.ActionBuilder var actions: [Self.Action] { get }

Eylemler, TipView altında düğme olarak görünür. İsteğe bağlı birincil ve ikincil düğmeler sağlayarak kullanıcıların bir özelliği kullanmaya başlamasına veya daha fazla bilgi edinmesine yardımcı olur.

// Action başlatıcıları:
init(id: String?, title: some StringProtocol, perform: () -> Void)
init(id: String?, perform: () -> Void, () -> Text) // Özel etiketli

Durum İzleme

| Özellik / Yöntem | Tip | Açıklama | | --- | --- | --- | | status | Status | Kurallara ve gösterim sıklığına dayalı mevcut durum | | statusUpdates | AsyncStream<Status> | Durum değişikliklerini izlemek için asenkron akış | | shouldDisplay | Bool | Görüntülenip görüntülenmeyeceğini belirleyen değer | | shouldDisplayUpdates | AsyncMapSequence<...> | Görüntülenme uygunluğunu izlemek için asenkron akış |

Durum değerleri (Tips.Status):

| Durum | Açıklama | | --- | --- | | .available | İpucu görüntülenmeye uygun | | .pending | İpucu görüntülenmeye uygun değil | | .invalidated(reason) | İpucu artık geçerli değil |

Geçersiz kılma nedenleri (Tips.InvalidationReason):

| Neden | Açıklama | | --- | --- | | .actionPerformed | Kullanıcı ipucunun açıkladığı eylemi gerçekleştirdi | | .tipClosed | Kullanıcı ipucu görünümünü açıkça kapattı | | .displayCountExceeded | Maksimum gösterim sayısı aşıldı | | .displayDurationExceeded | Maksimum gösterim süresi aşıldı |

Geçersiz Kılma ve Sıfırlama

// İpucunu kalıcı olarak geçersiz kıl
func invalidate(reason: Self.InvalidationReason)

// Daha önce geçersiz kılınmış bir ipucunu sıfırla (iOS 26+)
func resetEligibility() async

resetEligibility(), geçersiz kılınmış bir ipucunun durumunu .pending veya .available'a geri döndürerek yeniden görüntülenmeye uygun hale getirir.


TipGroup

Sınıf | TipKit

*iOS 18.0+, iPadOS 18.0+, Mac Catalyst 18.0+, macOS 15.0+, tvOS 18.0+, visionOS 2.0+, watchOS 11.0+*

Belirli bir sıra veya uygunluk durumuna göre tek tek sunulabilen ipucu koleksiyonu.

final class TipGroup

İpuçlarını belirli bir sırayla (TipGroup.Priority.ordered) veya uygun ilk ipucunu (TipGroup.Priority.firstAvailable) gösterecek şekilde gruplandırabilirsiniz. Varsayılan öncelik firstAvailable'dır.

struct TrailDetails: View {
    let trail: Trail

    @State
    var trailDetailTips = TipGroup {
        FindTrailheadTip()
        ExposureRatingTip()
        SlopeProfileTip()
    }

    var body: some View {
        ScrollView(.vertical) {
            Text(trail.name).font(.title)

            NavigateToTrailButton(trailLocation: trail.location)
                .popoverTip(trailDetailTips.currentTip as? FindTrailheadTip)

            TipView(trailDetailTips.currentTip as? ExposureRatingTip, arrowEdge: .bottom)
            Text("Maruziyet Derecesi: \(trail.exposureRating)")

            TipView(trailDetailTips.currentTip as? SlopeProfileTip, arrowEdge: .bottom)
            Text("Eğim Açısı: \(trail.slopeAngle)°")
        }
    }
}

API Referansı

// Oluşturma
init(_ priority: TipGroup.Priority = .firstAvailable,
     @Tips.GroupBuilder _ builder: () -> [any Tip])

Öncelik:

| Durum | Açıklama | | --- | --- | | .firstAvailable | Uygun olan ilk ipucunu gösterir | | .ordered | Önceki tüm ipuçlar geçersiz kılındığında sıradaki ipucunu gösterir |

Mevcut ipucuna erişim:

@MainActor final var currentTip: (any Tip)? { get }
final var currentTipUpdates: some AsyncSequence<any Tip, Never> { get }

Uyum

  • Observable, Sendable