The hoverEffect closure modifier builds a custom reaction for when the user looks at a view on
visionOS, or points at it on macOS and tvOS. A CustomHoverEffect type makes the effect reusable.
The hoverEffect closure
The closure works like visualEffect. It hands you an empty effect stub to chain effects onto,
an isActive flag that turns true while the user hovers, and a GeometryProxy for the view's
geometry.
Button("Play", systemImage: "play.fill") { }
.labelStyle(.iconOnly)
.hoverEffect { effect, isActive, geometry in
effect.scaleEffect(isActive ? 1.1 : 1.0)
}
Delay the effect with animation
Many hover effects firing as the user looks around clutters the experience. Call animation on
the effect stub to delay activation, which matters most when the effect changes the view's size.
.hoverEffect { effect, isActive, geometry in
effect.animation(.default.delay(isActive ? 0.8 : 0.2)) {
$0.scaleEffect(isActive ? 1.1 : 1.0)
}
}
Reuse with CustomHoverEffect
Wrap the closure in a type that conforms to CustomHoverEffect. The only requirement is a
body(content:) function, and the closure body moves in unchanged.
struct ScaleEffect: CustomHoverEffect {
func body(content: Content) -> some CustomHoverEffect {
content.hoverEffect { effect, isActive, geometry in
effect.animation(.default) {
$0.scaleEffect(isActive ? 1.1 : 1.0)
}
}
}
}
// usage
.hoverEffect(ScaleEffect())