How it works
HoverEffectPhaseOverride lets you drive a hover effect to a specific phase yourself, rather than leaving its active state entirely to the system's pointer tracking. A hover effect normally transitions between its resting and active phases as a pointer enters and leaves a view, and the closure form of hoverEffect(_:) hands you the current phase so you can shape that transition. Reach for the override when you need a view to read as hovered (or not) independently of where the pointer actually is — for example to mirror a selection, reflect focus, or force the effect during a programmatic interaction.
Apply the customizable hover effect with hoverEffect(_:)
The closure-based
hoverEffect(_:)modifier is where the override surfaces. It attaches a hover effect to a view and calls back as the phase changes, letting you compose the effect's appearance for each phase. In the example the modifier wraps theText("Hover me")card built from.padding()and.background(.blue.opacity(0.15), in: .rect(cornerRadius: 12)).Receive the effect, active state, and phase override in the closure
The closure is handed the base
effectto build on, anisActiveflag for whether the effect is currently engaged, and a third parameter — the phase override — that reports any forced phase. In the demo these arrive as{ effect, isActive, _ in ... }, with the override position bound to_because the view simply tracks real pointer state.Branch your styling on the resolved phase
Inside the closure you read the active/inactive distinction and configure the effect accordingly, so the same view describes both its resting and hovered looks in one place. Here
effect.scaleEffect(isActive ? 1.1 : 1.0)grows the card to 110% only while the effect is active and returns it to1.0otherwise.Animate the phase change with animation(_:value:)
Because the phase is a value that flips between states, you animate the override the way you would any state change — by attaching
.animation(_:value:)keyed to the same flag. The example uses.animation(.easeInOut, value: isActive)so the scale interpolates smoothly each time the effect's phase changes instead of snapping.
_ in { effect, isActive, _ in ... } with a named phase-override binding and drive scaleEffect from it instead of isActive to see the effect honor a forced phase rather than the live pointer.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct HoverEffectPhaseOverrideDemo: View {
var body: some View {
VStack(spacing: 16) {
Text("Hover Effect")
.font(.headline)
Text("Hover me")
.padding()
.background(.blue.opacity(0.15), in: .rect(cornerRadius: 12))
.hoverEffect { effect, isActive, _ in
effect
.scaleEffect(isActive ? 1.1 : 1.0)
.animation(.easeInOut, value: isActive)
}
}
.padding()
}
}