TL;DR: 在 iOS 18 中,通过
TipGroup
可以按顺序展示提示,确保用户按开发者预设的步骤接收提示信息。在 iOS 17 中,可通过自定义参数和规则实现类似功能。示例代码展示了TipGroup
的基础用法和如何自定义提示逻辑。
背景
TipKit 可帮助用户发现新功能或提升效率,但默认情况下,提示不会按开发者预设的顺序展示。以下将探讨如何在不同 iOS 版本中实现按顺序显示提示。
使用 TipGroup(iOS 18)
在 iOS 18 中,TipKit 引入了 TipGroup
,使开发者可以将多个 Tip 组合在一起,按顺序显示满足条件的提示。
示例代码
Swift
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) { // 创建按顺序显示的 TipGroup
Tip1()
Tip2()
}
var body: some View {
VStack {
Text("Hello World")
.popoverTip(tips.currentTip) // 显示满足条件的当前提示
Button("Start Show Tips") {
Tip1.show = true // 激活 Tip1
}
.buttonStyle(.bordered)
}
}
}
示例效果
在多个组件中使用 TipGroup
开发者可以在不同组件中复用同一个 TipGroup
,确保仅展示符合条件的提示:
Swift
var body: some View {
VStack(spacing: 80) {
Text("Hello World")
.popoverTip(tips.currentTip as? Tip1) // 对应 Tip1
Text("Fatbobman's Blog")
.popoverTip(tips.currentTip as? Tip2) // 对应 Tip2
Button("Start Show Tips") {
Tip1.show = true
}
.buttonStyle(.bordered)
}
}
示例效果
提示: 在有序的
TipGroup
中,后续提示仅在前置提示被无效化后显示。
自定义顺序显示方案(iOS 17)
在 iOS 17 中,由于缺少 TipGroup
,可以通过自定义参数和规则创建类似效果。
实现步骤
- 定义自定义参数和规则
在 Tip 中使用参数
show
控制显示条件。 - 声明自定义样式
在自定义
TipViewStyle
中,点击关闭按钮后激活下一个提示。
示例代码
Swift
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 // 激活下一个提示
}
}
.padding()
}
}