admin管理员组

文章数量:1122832

When using a stylus or a mouse on the iPad, hovering over a text button causes it to get highlighted. Unfortunately, the highlighted area does not match the size of the button. How can I make hover-highlighted area to match the size of the button?

Here is an image to demonstrate it (notice the pale gray hover and red border of a real button)

And here is the min.code to see for yourself (run in the simulator and use "Capture Pointer" (looks like a "sun with rays" button)):

struct SOQuestionView: View {
    var body: some View {
        NavigationStack {
            Text("Hello, World!")
                .toolbar {
                    ToolbarItemGroup(placement: .principal) {
                        Button("B") {}
                            .border(Color.red)
                    }
                }
        }
    }
}

P.S. Why do I need it? - I want to give background to that button. But when I hover over it, you guessed it - the hover background doesn’t align with the actual button's background.

When using a stylus or a mouse on the iPad, hovering over a text button causes it to get highlighted. Unfortunately, the highlighted area does not match the size of the button. How can I make hover-highlighted area to match the size of the button?

Here is an image to demonstrate it (notice the pale gray hover and red border of a real button)

And here is the min.code to see for yourself (run in the simulator and use "Capture Pointer" (looks like a "sun with rays" button)):

struct SOQuestionView: View {
    var body: some View {
        NavigationStack {
            Text("Hello, World!")
                .toolbar {
                    ToolbarItemGroup(placement: .principal) {
                        Button("B") {}
                            .border(Color.red)
                    }
                }
        }
    }
}

P.S. Why do I need it? - I want to give background to that button. But when I hover over it, you guessed it - the hover background doesn’t align with the actual button's background.

Share Improve this question asked Nov 23, 2024 at 5:17 AnnaAnna 717 bronze badges 1
  • That gray rectangle is supposed to be an enlarged version of the pointer. It doesn't make sense for it to fit exactly inside the button's border. You can even slightly move the gray rectangle around. – Sweeper Commented Nov 23, 2024 at 8:45
Add a comment  | 

2 Answers 2

Reset to default 1

The default hover effect depends on the ButtonStyle used for the button.

  • The button style in your example is .automatic and the default effect is .highlight.

  • None of the other built-in button styles seem to have a default hover effect, but you can turn an effect on by applying a .hoverEffect modifier.

So one workaround for the mis-fitting highlight shape is to use a button style with a more defined size and apply .hoverEffect(.highlight) to it.

  • If you choose .plain or .borderless as button style then you will probably want to add padding too.

  • If you want the hover effect to be shown as soon as the mouse cursor enters the frame, as opposed to when it reaches the text of the label, apply .contentShape(Rectangle()) to the padded button.

Using this approach with your example:

Button("B") {}
    .buttonStyle(.borderless)
    .padding()
    .contentShape(Rectangle())
    .hoverEffect(.highlight)
    .border(.red)

If you want to use the same modifiers for other buttons too, it would be simpler to define a custom ButtonStyle that encapsulates this styling and behavior:

struct MyHoverButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding()
            .contentShape(Rectangle())
            .foregroundStyle(.tint)
            .hoverEffect(.highlight)
    }
}
Button("B") {}
    .buttonStyle(MyHoverButtonStyle())
    .border(.red)

With a custom button style, you could also apply your own styling when hover is in effect:

  • Detect hover state yourself using an .onHover callback.
  • A .transition can be used to add a bit of animation.
struct MyHoverButtonStyle: ButtonStyle {
    @State private var withHover = false

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding()
            .foregroundStyle(.tint)
            .background {
                if withHover {
                    RoundedRectangle(cornerRadius: 10)
                        .fill(.yellow.opacity(0.5))
                        .scaleEffect(1.1)
                        .transition(.scale.animation(.easeInOut(duration: 0.1)))
                }
            }
            .onHover { isHovering in
                withHover = isHovering
            }
    }
}

This is the .highlight hover effect.

For pointer input this effect morphs the pointer into a platter behind the view and shows a light source indicating position.

The gray rectangle is not a fixed shape that highlights the button, but rather the pointer itself. It is not designed to fit the button's frame - you can move it around just like a normal pointer. The actual position of the pointer is indicated by a "light source" - an area where the gray color is slightly lighter.

Unfortunately making your own hover effects is not an option on iOS (only available on visionOS), so if you want to change the highlight's frame to fit the button, you can try something like in Benzy Neez's answer.

You can remove the effect simply using .hoverEffectDisabled(), without changing the button style.

Alternatively, if you still want something to happen on hover, you can use .defaultHoverEffect(.lift), which just enlarges the button a little bit, and IMO doesn't look as bad.

本文标签: swiftuiHow to change the size of onHover background of a buttonStack Overflow