SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App

SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App_第1张图片

概览

作为我们秃头开发者来说,写出一款创意炸裂的 App 还不足以吸引用户眼球,更重要的是如何让用户用最短的时间掌握我们 App 的使用技巧。

从 iOS 17 开始, 推出了全新的 TipKit 框架专注于此事。有了它,我们再也不用自己写 App 用户帮助以及使用指南的逻辑和界面了。

使用 TipKit 非常简单,接下来就让我们一起走进 TipKit 的世界吧!

文章目录

  • 概览
  • 什么是 TipKit?
  • 创建一个 Tip
  • TipKit 显示的两种方式
  • TipKit 全局配置
  • TipKit 显示规则
  • 为 TipKit 增加更多互动性
  • 如何测试 TipKit?
  • 总结

本文代码全部在 Xcode 15 beta8 上编译,在 iOS 17 beta8 上运行。


什么是 TipKit?

TipKit 是  在 WWDC 23 上推出的一款新框架,用于在界面显示提示(Tips)来帮助用户快速发掘我们 App 的使用特性。

SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App_第2张图片
SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App_第3张图片

目前该框架仍属于 beta 阶段,意味着它还有很多不确定性。

如果我没有记错, 直到 Xcode beta4 才将 TipKit 提供给开发者,而且现在 官网 TipKit 的示例代码在 Xcode beta8 中已提示语法错误了(我们后面会说明):

在这里插入图片描述


对于  这种习惯性“谜之”行为的更多细节,感兴趣的小伙伴们可以到如下链接中观赏:

  • 有用的知识又增加了:为何无法编译某些  WWDC 官方视频中的代码?

创建一个 Tip

按照 SwiftUI 的“习性”,一个 Tip 同时意味着外观和逻辑双重含义。

创建一个提示很简单,只需遵循 Tip 协议即可:

struct FavoriteTip: Tip {
    var title: Text {
        Text("收藏最爱的图片")
            .bold()
    }
    
    var message: Text? {
        Text("将心仪的图片保存到相册中")
            .font(.headline)
            .foregroundStyle(.gray.gradient)
    }
}

Tip 协议还有很多其它可选属性,比如我们还可以为 Tip 界面进一步增加图片修饰:

struct FavoriteTip: Tip {
    var image: Image? {
        Image(systemName: "heart")
    }
}

TipKit 显示的两种方式

在 Tip 创建之后如何显示它们呢?有两种方式:嵌入和弹出。

我们可以直接将 Tip 嵌在视图中:

struct ContentView: View {
    let favTip = FavoriteTip()
    
    var body: some View {
        NavigationStack {
            VStack {
                
                TipView(favTip)
            }
            .padding()
            .navigationTitle("TitKit演示")
        }
    }
}

显示效果如下:

SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App_第4张图片

或者我们还可以将 Tip 直接依附于某一个视图,比如图片或按钮:

struct ContentView: View {
    let favTip = FavoriteTip()
    
    var body: some View {
        NavigationStack {
            VStack {...}
            .padding()
            .navigationTitle("TitKit演示")
            .toolbar {
                ToolbarItem {
                    Image(systemName: "heart")
                        .font(.title.weight(.black))
                        .foregroundStyle(.pink.gradient)
                        .popoverTip(favTip, arrowEdge: .top)
                }
            }
        }
    }
}

SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App_第5张图片

我们可以根据不同需求来组合使用这两种显示方式。

TipKit 全局配置

其实,TipKit 框架会在 App (本地目录)中存放一些相关的配置信息。理论上说,它们可能会通过 iCloud 同步到其它设备上去,这意味着在不同设备上相同 App 中的 TipKit 共享同一组配置。

我们可以进一步定制 TipKit 的配置细节,比如 Tip 显示频率、配置数据库保存的本地位置等等:

import SwiftUI
import TipKit

@main
struct TipKitTestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .task {                    
                    try? Tips.configure([
                        .displayFrequency(.immediate),
                        .datastoreLocation(.applicationDefault)
                    ])
                    
                    // Xcode 15 beta4 中过时的语法,目前已不能使用:
                    /*
                    try? await Tips.configure {
                        DisplayFrequency(.immediate)
                        DatastoreLocation(.applicationDefault)
                    }*/
                }
        }
    }
}

如上代码所示,我们需要所有 Tip 立即显示,并且让系统决定配置数据存储的位置(我们也可以自己设置存储路径)。

在代码中,我们注释了之前官方示例中出错的代码片段,这些代码在 Xcode 15 beta8 中已不能使用。

TipKit 显示规则

除了全局 Tip 显示限制以外,我还可以设置单个 Tip 之间的显示规则。

比如,假设有两个提示,我们希望 FavoriteTip 在 StartTip 提示关闭后再显示,我们可以在 FavoriteTip 中用特定的规则(Rule)来表示这一约束:

struct FavoriteTip: Tip {
    // 其它代码从略
    
    var rules: [Rule] {
        #Rule(Self.$startTipHasDisplayed) { $0 == true}
    }
    
    @Parameter
    static var startTipHasDisplayed: Bool = false
    
}

现在,我们需要在 StartTip 提示关闭时将 FavoriteTip.startTipHasDisplayed 置为 true 才能触发 FavoriteTip 的显示:

struct ContentView: View {
    
    let startTip = StartTip()
    let favTip = FavoriteTip()
    
    var body: some View {
        NavigationStack {
            
            VStack {
                
                Image("1")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .onTapGesture {
                        // 关闭 startTip 提示
                        startTip.invalidate(reason: .actionPerformed)
                        // 触发 FavoriteTip 提升的显示
                        FavoriteTip.startTipHasDisplayed = true
                    }
                
                TipView(startTip)
            }
            .padding()
            .navigationTitle("TitKit演示")
            .toolbar {
                ToolbarItem {
                    Image(systemName: "heart")
                        .font(.title.weight(.black))
                        .foregroundStyle(.pink.gradient)
                        .popoverTip(favTip, arrowEdge: .top)
                }
            }
        }
    }
}

现在,只有等 StartTip 关闭后,FavoriteTip 提示才能显示出来:
SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App_第6张图片

为 TipKit 增加更多互动性

有时,我们希望提示为用户提供更丰富的交互功能,比如在 Tip 中提供按钮跳转到更详细的使用教程界面。

TipKit 为此也提供了很好的支持,我们可以为 Tip 添加 Action 来驱动交互行为:

struct FavoriteTip: Tip {
    // 其它代码从略
    
    var actions: [Action] {
        [
            Tip.Action(id: "learn-more", title: "了解更多"),
            Tip.Action(id: "forget", title: "下次再说")
        ]
    }
}

在 Tip Action 被触发时,我们可以执行自定义行为:

struct ContentView: View {
    
    let startTip = StartTip()
    let favTip = FavoriteTip()
    
    var body: some View {
        NavigationStack {
            
            VStack {
                
                Image("1")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .onTapGesture {
                        startTip.invalidate(reason: .actionPerformed)
                        
                        FavoriteTip.startTipHasDisplayed = true
                    }
                
                TipView(startTip)
            }
            .padding()
            .navigationTitle("TitKit演示")
            .toolbar {
                ToolbarItem {
                    Image(systemName: "heart")
                        .font(.title.weight(.black))
                        .foregroundStyle(.pink.gradient)
                        .popoverTip(favTip, arrowEdge: .top){ action in
                            switch action.index {
                            case 0:
                                favTip.invalidate(reason: .tipClosed)

                                // 跳转到详细使用教程
                            case 1:
                                favTip.invalidate(reason: .tipClosed)
                                
                                // 直接退出提示
                            default:
                                break
                            }
                        }
                }
            }
        }
    }
}

现在,用户可以选择“了解更多”来进一步学习 App 的使用“秘技”了:

如何测试 TipKit?

TipKit 全局配置存储在本地带有持久化特性,为了便于开发者即时测试, 提供了一些方法来快速显示或隐藏全部或指定 Tip:

SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App_第7张图片

一般的,要想在 Xcode 预览中正确测试 TipKit 的行为,我们需要在每次视图刷新时重置 TipKit 数据库,否则 Tip 不会正常显示:

#Preview {
    ContentView()
        .task {
            // 在每次视图刷新时将 TipKit 数据库重置为初始状态
            try? Tips.resetDatastore()
            
            try? Tips.configure([
                .displayFrequency(.immediate),
                .datastoreLocation(.applicationDefault)
            ])
        }
}

总结

在本篇博文中,我们介绍了 SwiftUI 5.0(iOS 17)中新引进的开发框架 TipKit,使用它我们可以非常方便和快速的向用户介绍我们 App 中的各种特性和使用指南,小伙伴们还不快操练起来!

感谢观赏,再会!

你可能感兴趣的:(Apple开发入门,iOS,17,SwiftUI,5.0,TipKit,Xcode,15,Tip,提示)