0

I want to write my own button style which behaves like those in macOS menu list.

As it shown below, after click, its background changed: blue -> transparent -> blue, and then disappear. And they all happen after releasing, so I don't think configuration.isPressed can help.

enter image description here

I tried following code, but they didn't perform correctly. No animation at all. And even worse, "hovering to show blue background" is animated.

I only want that "blink" effect after I release my mouse, instead affecting animation before I releasing it. I don't know where to go next. Please help me out.

@State var onHover: Bool = false

public func makeBody(configuration: Configuration) -> some View {
    configuration.label
        .background {
            onHover ? Color.accentColor : Color.clear
        }
        .onHover { onHover = $0 }
        .animation(.easeOut(duration: 0.1))
        .onTapGesture {
            onHover = false        // Blinking here
            onHover = true
        }
}
Yiming Designer
  • 423
  • 3
  • 10

2 Answers2

2
struct CustomButton: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        let isPressed = configuration.isPressed
        let backgroundColor = isPressed ? Color.blue.opacity(0.2) : Color.clear
        
        return configuration.label
            .padding(EdgeInsets(top: 4, leading: 12, bottom: 4, trailing: 12))
            .background(backgroundColor)
            .onHover { isHovering in
                if !isHovering {
                    withAnimation {
                        configuration.isPressed = false
                        configuration.isOn = true
                    }
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                        withAnimation {
                            configuration.isOn = false
                        }
                    }
                }
            }
            .opacity(configuration.isOn ? 0.0 : 1.0)
            .animation(.easeInOut(duration: 0.2), value: configuration.isOn)
    }
}

Button("Click me") {}
    .buttonStyle(CustomButton())
0

Inspired by Mark Roberts's answer, I have my code as below eventually. I hope it's more clear and easy to read.

@State var onHover: Bool = false

public func makeBody(configuration: Configuration) -> some View {
    configuration.label
        .padding()
        .background { onHover ? Color.accentColor : Color.clear }
        .onHover { onHover = $0 }
        .onChange(of: configuration.isPressed) {
            // Blinking here
            if $0 == false {
                onHover = false
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.06) {
                    onHover = true
                }
            }
        }
}
Yiming Designer
  • 423
  • 3
  • 10