Jordan H
Jordan H

Reputation: 55715

How to customize hover effect region in visionOS

In the Design for spatial user interfaces WWDC video around 13:00 Apple states the following in regards to hover effects:

As you're designing a lock-up, include a shape that will allow the system to display the hover effect as people focus on it. Here, we have some images with text below them. Each lock-up is a single interactive element. You need to define a custom region so it can brighten as people look at it. This helps them understand the entire area is a single element that can be selected. And remember to keep that small space in between each containing shape.

They include examples from Music app:

Music app screenshot 1 Music app screenshot 2

I'd like to do this in my app that displays Buttons in a LazyVGrid but haven't been able to achieve that result. I know you need to use the plain button style to hide the border button's background yet keep the hover effect. The hover effect appears as an oval though, instead I want it to be a rounded rectangle with additional padding around it and 4pt spacing between the hover effects, as is shown above. How can this be done? I thought .contentShape(.hoverEffect, .rect(cornerRadius: 50)) would customize the region but it doesn't seem to change anything.

Button(action: tapAction) {
    VStack {
        Color.clear
            .background(.regularMaterial)
            .aspectRatio(1, contentMode: .fit)
            .clipShape(.rect(cornerRadius: 10))
            
        HStack(spacing: 0) {
            VStack(alignment: .leading, spacing: 0) {
                Text("Line one")
                
                Text("Line two")
                    .foregroundStyle(.secondary)
            }
            
            Spacer()
            
            MarkWateredButton(action: markWateredAction)
        }
    }
    .contentShape(.hoverEffect, .rect(cornerRadius: 50).inset(by: -10)) // FIXME: Doesn't do anything
}
.buttonStyle(.plain)

Screenshot from my app

Upvotes: 4

Views: 2228

Answers (4)

AmirZ
AmirZ

Reputation: 401

It seems like calling .hoverEffect() without a parameter does not disable the hover effect anymore. Instead, you should call .hoverEffectDisabled(true) like so:

Button {
    //action
} label: {
    Text(someText)
        .frame(width: 75,
               alignment: .leading)
        .minimumScaleFactor(0.75)
}
.hoverEffectDisabled(true)

Upvotes: 0

Hidde van der Ploeg
Hidde van der Ploeg

Reputation: 211

Yeah like YichenBman says, you do need .hoverEffect(). As a bonus, your background cornerRadius is 10. So the outer radius should be 20 with a padding of 10 to look nice and matching 😄.

Button(action: tapAction) {
    VStack {
        Color.clear
            .background(.regularMaterial)
            .aspectRatio(1, contentMode: .fit)
            .clipShape(.rect(cornerRadius: 10))
            
        HStack(spacing: 0) {
            VStack(alignment: .leading, spacing: 0) {
                Text("Line one")
                
                Text("Line two")
                    .foregroundStyle(.secondary)
            }
            
            Spacer()
            
            MarkWateredButton(action: markWateredAction)
        }
    }
    .padding(10)
    .contentShape(.hoverEffect, .rect(cornerRadius: 20)) 
    .hoverEffect()
}
.buttonStyle(.plain)

Upvotes: 8

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119310

Demo

You just need to apply the .buttonBorderShape modifier:

Button() label: { ... }
    .buttonBorderShape(.roundedRectangle)

Upvotes: 1

YichenBman
YichenBman

Reputation: 5651

https://developer.apple.com/videos/play/wwdc2023/10094/?time=60 This WWDC video is helpful.

You need to add the .hoverEffect() modifier to the Stack

Upvotes: 2

Related Questions