I’ve encountered an issue when attempting to add multiple popoverTip modifiers in my SwiftUI code. Regardless of whether there’s a specified rule or parameter, the tips begin to constantly appear and disappear. Is this a recognized issue? How can we sequentially display multiple tip popovers on complex views? Even when one tip is invalidated, the glitch persists. Should this be used only for views without any state updates?
Here’s a sample code that demonstrates the problem:
import SwiftUI
import TipKit
@main
struct testbedApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
init() {
try? Tips.configure()
}
}
struct PopoverTip1: Tip {
var title: Text {
Text("Test title 1").foregroundStyle(.indigo)
}
var message: Text? {
Text("Test message 1")
}
}
struct PopoverTip2: Tip {
var title: Text {
Text("Test title 2").foregroundStyle(.indigo)
}
var message: Text? {
Text("Test message 2")
}
}
struct ContentView: View {
private let timer = Timer.publish(every: 0.001, on: .main, in: .common).autoconnect()
@State private var counter = 1
var body: some View {
VStack(spacing: 20) {
Spacer()
Text("Counter value: (counter)").popoverTip(PopoverTip1())
Spacer()
Text("Counter value multiplied by 2: (counter * 2)")
.foregroundStyle(.tertiary)
.popoverTip(PopoverTip2())
Spacer()
}
.padding()
.onReceive(timer) { _ in
counter += 1
}
}
}
#Preview {
ContentView()
}
2
Answers
It would seem so. You can certainly get it to work by avoiding updates in the view that is showing the tips.
It works with the following changes:
ObservableObject
that is created (but not observed) in the parent view.Text
views to separate views and pass them the wrapped counter to observe.With just these changes to your original code, it works to the extent that tip 1 is shown every time you restart the app, but tip 2 is never shown. In order that tip 1 is recorded as seen, you need to add a tap gesture that invalidates the tip, as explained in the documentation. Then, the next time you start the app, tip 2 is shown.
Here is your example with all the changes applied:
To reset all tips (for testing purposes), add a line to purge the tips to the
init
function of the app, beforeTips.configure()
:It is a bit hacky and fragile but you can use a shared hardcoded
Event
Rule
to present sequential tips.Each
Tip
would have a hardcodedcount
.Then
onReceive
send a donation.It is a bit tacky because from my testing the hardcoded count has to be "odd"
If they are sequential the "even" get skipped.
I used the documentation for the
Tips.Event
screen on the Apple website.https://developer.apple.com/documentation/tipkit/tips/event
The logic behind this solution is that only one tip is eligible to be shown at a time.
It seems like tip kit evaluates what tips to show at every reload of the body and presents/dismisses anything that is eligible. I think this is intentional but a bug report wouldn’t hurt.