如何实现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
相关产品推荐
相关产品推荐

