Displaying tips based on parameters and events with TipKit
Learn how to trigger tips based on parameters and events with TipKit in a SwiftUI app.
In the tutorial Using TipKit on a SwiftUI app, we saw how helpful the TipKit framework is to help users discover our app's main feature. Now let's set up the tips so they are displayed after specific user interactions using Parameter and Event rules.
Tips.configure()
method and when testing your tips use the Tips.resetDatastore()
method to reset any dismissal state.Showing the tips using parameter rules
Consider the case where you want to display a specific tip after the user interacts with a button or performs a particular action. We can define a property inside the tip declaration that allows us to present it only after a certain condition is met.
A type that monitors the state of its wrapped value to reevaluate any dependent tip rules when the value changes.
Using the @Parameter
property wrapper we can monitor the state of a value to reevaluate the rules of a tip. After that, we can add a Rule
inside our tip using the #Rule
macro to set the condition for presenting the tip inside the app.
import TipKit
struct ParameterRuleTip: Tip {
// Value to be tracked to reevaluate the Rules
@Parameter
static var isTipPresented: Bool = false
// Rules to control when a tip is displayed
var rules: [Rule] {
[
#Rule(Self.$isTipPresented) {
$0 == true
}
]
}
var title: Text {
Text("Parameter Rule")
}
var message: Text? {
Text("You can present this tip only when the property is true")
}
var image: Image? {
Image(systemName: "swift")
}
}
In the example above the tip will be shown in the app only when the isFavoritePressed
property is set to true. We can access this property inside the View
and display the tip using the TipView
component.
import SwiftUI
import TipKit
struct ContentView: View {
let parameterRuleTip = ParameterRuleTip()
var body: some View {
VStack {
// Tip to be presented
TipView(parameterRuleTip)
.padding()
Button {
// Toggling the parameter value
ParameterRuleTip.isTipPresented.toggle()
} label: {
Text("Show a tip")
}
.buttonStyle(.borderedProminent)
}
.padding()
// For testing purposes
.onAppear {
try? Tips.resetDatastore()
try? Tips.configure()
}
}
}
Clicking on the button the user will visualize the tip that we defined.
Showing the tips based on events
You can also consider showing your tip only after a user accesses a particular view many times. It can be useful to bring awareness to a feature on that view the user isn't aware of. We can define this type of rule using the Event
type.
Using Event
we can monitor actions occurring one or multiple times within the app. Each time the action happens, we'll "donate" to the event, incrementing its count by one. This count will then determine whether the associated tips should be presented.
struct EventRuleTip: Tip {
static let eventVisualized = Event(id: "eventVisualized")
var title: Text {
Text("Event Rule tip")
}
var message: Text? {
Text("This tip is presented after the donation count is bigger than 3")
}
var image: Image? {
Image(systemName: "3.circle")
}
var rules: [Rule] {
[
#Rule(Self.eventVisualized) {
$0.donations.count > 3
}
]
}
}
In the example above, the tip will be presented when the donation count of the event is greater than three. In other words, the tip will be displayed after the fourth time the user accesses the same view.
We can donate to the event on our View
using the onAppear(perform:)
modifier and calling the donate()
method from the eventVisualized
property.
import SwiftUI
import TipKit
struct ContentView: View {
@State var showView: Bool = false
var body: some View {
Button {
showView.toggle()
} label: {
Text("Show the view!")
}
.sheet(isPresented: $showView, content: {
VisualizedView()
})
// For testing purposes
.onAppear {
try? Tips.configure()
}
}
}
struct VisualizedView: View {
var eventRuleTip = EventRuleTip()
var visualizations: Int {
EventRuleTip.eventVisualized.donations.count + 1
}
var body: some View {
VStack {
Text("Hello!").font(.title2).bold()
Text("You saw me **\(visualizations)** times")
TipView(eventRuleTip)
.padding()
}
.onAppear {
Task {
await EventRuleTip.eventVisualized.donate()
}
}
}
}