You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SwiftUI中实现类似macOS菜单列表的按钮闪烁效果?

实现macOS菜单风格按钮点击闪烁效果

要实现点击释放后蓝色→透明→蓝色→消失的闪烁效果,核心是拆分悬停与点击的状态控制,并通过时序动画实现多步状态切换。你的原有代码问题在于用同一个变量同时控制悬停和点击动画,且未处理点击后的状态延迟切换,导致动画冲突且无闪烁效果。

解决方案代码

@State private var hovered = false
@State private var isBlinking = false

public func makeBody(configuration: Configuration) -> some View {
    configuration.label
        .background {
            // 显示优先级:点击闪烁 > 悬停高亮
            if isBlinking {
                Color.accentColor
            } else if hovered {
                Color.accentColor
            } else {
                Color.clear
            }
        }
        .onHover { newValue in
            // 悬停状态即时切换,无动画(贴合macOS原生菜单体验)
            hovered = newValue
        }
        .onTapGesture {
            startBlinking()
        }
}

private func startBlinking() {
    // 第一步:立即显示蓝色
    withAnimation(.easeOut(duration: 0.1)) {
        isBlinking = true
    }
    
    // 第二步:延迟0.1秒切换为透明
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        withAnimation(.easeOut(duration: 0.1)) {
            isBlinking = false
        }
    }
    
    // 第三步:延迟0.2秒再次显示蓝色
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
        withAnimation(.easeOut(duration: 0.1)) {
            isBlinking = true
        }
    }
    
    // 第四步:延迟0.3秒恢复透明,结束闪烁
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
        withAnimation(.easeOut(duration: 0.1)) {
            isBlinking = false
        }
    }
}

关键说明

  • 状态拆分:用hovered控制悬停高亮,isBlinking控制点击后的闪烁效果,彻底避免状态冲突。
  • 动画隔离:悬停状态切换无动画,保持原生菜单的即时反馈;点击闪烁的每一步状态切换单独绑定动画,确保仅闪烁过程有过渡效果。
  • 时序控制:通过DispatchQueue.main.asyncAfter实现精准的延迟切换,完美复刻蓝→透明→蓝→消失的闪烁节奏。
  • 优先级处理:背景颜色判断优先响应isBlinking状态,确保点击闪烁时覆盖悬停效果,符合交互逻辑。

内容的提问来源于stack exchange,提问作者Yiming Designer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:23:06