Solution #1: Check for .onHover(...)
Use the .onHover(perform:) view modifier to toggle a @State property to keep track of whether your tooltip should be displayed:
@State var itemHovered: Bool = false
var body: some View {
content
.onHover { hover in
itemHovered = hover
}
.overlay(
Group {
if itemHovered {
Text("This is a tooltip")
.background(Color.white)
.foregroundColor(.black)
.offset(y: -50.0)
}
}
)
}
Solution #2: Make a Tooltip Wrapper View
Create a view wrapper that creates a tooltip view automatically:
struct TooltipWrapper<Content>: View where Content: View {
@ViewBuilder var content: Content
var hover: Binding<Bool>
var text: String
var body: some View {
content
.onHover { hover.wrappedValue = $0 }
.overlay(
Group {
if hover.wrappedValue {
Text("This is a tooltip")
.background(Color.white)
.foregroundColor(.black)
.offset(y: -50.0)
}
}
)
}
}
Then you can call with
@State var hover: Bool = false
var body: some View {
TooltipWrapper(hover: $hover, text: "This is a tooltip") {
Image(systemName: "arrow.right")
Text("Hover over me!")
}
}
From this point, you can customize the hover tooltip wrapper to your liking.
I wrote a Swift Package that makes SwiftUI a little easier for personal use, and it includes a tooltip view modifier that boils the solution down to:
import ShinySwiftUI
@State var showTooltip: Bool = false
var body: some View {
MyView()
.withTooltip(present: $showTooltip) {
Text("This is a tooltip!")
}
}
Notice you can provide your own custom views in the tooltip modifier above, like Image or VStack. Alternatively, you could use HoverView to get a stateful hover variable to use solely within your view:
HoverView { hover in
Rectangle()
.foregroundColor(hover ? .red : .blue)
.overlay(
Group {
if hover { ... }
}
)
}