Search code examples
swiftswiftuiswiftui-animation

How to make blink effect in SwiftUI?


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
        }
}

Solution

  • 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())