TL;DR: In iOS 18, use
TipGroup
to display tips in a specific order based on conditions. For iOS 17, achieve similar results with custom parameters and rules. Sample code demonstratesTipGroup
usage and custom logic for sequential tip display.
Background
TipKit helps users discover new features or improve efficiency, but by default, tips are not displayed in a developer-defined sequence. This guide explains how to achieve sequential tip display in different iOS versions.
Using TipGroup
(iOS 18)
In iOS 18, TipKit introduces TipGroup
, allowing developers to group multiple tips and display them sequentially based on specified conditions.
Sample Code
struct Tip1: Tip {
@Parameter static var show: Bool = false
var title: Text { Text("Tip1") }
var rules: [Rule] {
#Rule(Self.$show) { $0 }
}
}
struct Tip2: Tip {
var title: Text { Text("Tip2") }
}
struct TipGroupDemo: View {
@State var tips = TipGroup(.ordered) { // Create an ordered TipGroup
Tip1()
Tip2()
}
var body: some View {
VStack {
Text("Hello World")
.popoverTip(tips.currentTip) // Show the current active tip
Button("Start Show Tips") {
Tip1.show = true // Activate Tip1
}
.buttonStyle(.bordered)
}
}
}
Demonstration
Using TipGroup
Across Components
Developers can reuse a single TipGroup
across different components to ensure only the appropriate tip is displayed:
var body: some View {
VStack(spacing: 80) {
Text("Hello World")
.popoverTip(tips.currentTip as? Tip1) // Corresponding to Tip1
Text("Fatbobman's Blog")
.popoverTip(tips.currentTip as? Tip2) // Corresponding to Tip2
Button("Start Show Tips") {
Tip1.show = true
}
.buttonStyle(.bordered)
}
}
Demonstration
Tip: In an ordered
TipGroup
, subsequent tips are only displayed after the previous tips are invalidated.
Custom Sequential Display (iOS 17)
For iOS 17, which lacks TipGroup
, similar functionality can be implemented using custom parameters and rules.
Implementation Steps
- Define Custom Parameters and Rules
Use a
show
parameter in tips to control display conditions. - Declare Custom Styles
Use a custom
TipViewStyle
to activate the next tip when the close button is tapped.
Sample Code
import SwiftUI
import TipKit
struct Tip1: ShowTip {
var title: Text = Text("Step1 Tips")
@Parameter static var show: Bool = false
var rules: [Rule] {
[ #Rule(Self.$show) { $0 == true } ]
}
}
struct Tip2: ShowTip {
var title: Text = Text("Step2 Tips")
@Parameter static var show: Bool = false
var rules: [Rule] {
[ #Rule(Self.$show) { $0 == true } ]
}
}
struct ContentView: View {
private var tip1 = Tip1()
private var tip2 = Tip2()
var body: some View {
List {
Button("Show Tip1") {
Tip1.show = true
}
TipView(tip1, arrowEdge: .bottom)
.tipViewStyle(MyTipStyle(tip: Tip2.self))
Text("Step1")
TipView(tip2, arrowEdge: .bottom)
Text("Step2")
}
.padding()
}
}
protocol ShowTip: Tip {
static var show: Bool { get set }
}
struct MyTipStyle<T: ShowTip>: TipViewStyle {
let tip: T.Type
func makeBody(configuration: Configuration) -> some View {
VStack {
configuration.image?.font(.title2).foregroundStyle(.green)
configuration.title?.bold().font(.headline).textCase(.uppercase)
configuration.message?.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
.backgroundStyle(.thinMaterial)
.overlay(alignment: .topTrailing) {
Image(systemName: "multiply")
.font(.title2)
.foregroundStyle(.secondary)
.onTapGesture {
configuration.tip.invalidate(reason: .tipClosed)
tip.show = true // Activate the next tip
}
}
.padding()
}
}