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

如何实现SwiftUI按钮按下时背景动画消失的样式?

需求与问题

我需要实现一个按钮效果:按下按钮时,背景的阴影/动画层消失。之前尝试用ZStack嵌套两个Button的方式来实现,但不仅没达到预期效果,还存在重复初始化Button的问题,写法不够优雅。以下是我的复现代码:

import Foundation
import SwiftUI

struct TestButton<V: View>: View {
    @Environment(.colorScheme) var colorScheme: ColorScheme

    let content: V
    var foregroundStyle: Color? = nil

    var body: some View {
        ZStack {
            Button(action: {} ) {
                content
            }
            .padding(10)
            .background(Color(red: 0, green: 0, blue: 255/255))
            .applyDefaultCornerRadius()
            .offset(y: 5)

            Button(action: {}) {
                content
            }
            .padding(10)
            .background(Color.blue)
            .applyDefaultCornerRadius()
            .foregroundStyle(foregroundStyle ?? (colorScheme == .light ? Color.white : Color.black))
        }
    }
}

#Preview {
    TestButton(content: Text(verbatim: "Test"))
}
优化解决方案

可以通过单个Button结合状态变量和SwiftUI动画系统实现需求,代码更简洁优雅,避免重复初始化:

import SwiftUI

struct TestButton<V: View>: View {
    @Environment(.colorScheme) var colorScheme: ColorScheme
    @State private var isButtonPressed = false
    
    let content: V
    var foregroundStyle: Color? = nil

    var body: some View {
        Button(action: {}) {
            content
                .padding(10)
                .background(Color.blue)
                .applyDefaultCornerRadius()
                .foregroundStyle(foregroundStyle ?? (colorScheme == .light ? .white : .black))
                .offset(y: isButtonPressed ? 5 : 0)
                .animation(.easeInOut(duration: 0.1), value: isButtonPressed)
        }
        .background(
            // 仅在未按压时显示背景层
            Group {
                if !isButtonPressed {
                    Color(red: 0, green: 0, blue: 255/255)
                        .applyDefaultCornerRadius()
                        .offset(y: 5)
                }
            }
        )
        // 监听按压状态变化
        .onLongPressGesture(minimumDuration: 0, pressing: { isPressing in
            isButtonPressed = isPressing
        }, perform: {})
    }
}

// 补充自定义圆角扩展(假设原代码中有此实现)
extension View {
    func applyDefaultCornerRadius() -> some View {
        self.cornerRadius(8) // 可根据需求调整圆角大小
    }
}

#Preview {
    TestButton(content: Text(verbatim: "Test"))
}

关键实现说明

  • 状态跟踪:用@State private var isButtonPressed记录按钮的实时按压状态
  • 动画控制:按钮的偏移和背景层的显隐都绑定到isButtonPressed变量,配合animation实现平滑过渡
  • 按压监听:使用onLongPressGesture的pressing回调,能实时捕捉按钮按下/抬起的动作,比默认点击响应更精准
  • 结构优化:只保留一个Button实例,避免重复代码,结构更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 08:03:09