SwiftUI自定义进度按钮点击时文本延迟消失问题求助
SwiftUI加载按钮文本延迟消失问题解决
我在SwiftUI中创建了一个点击后进入加载状态的按钮,代码如下:
private struct Button1: View { @State var isLoading = false var body: some View { Button("Hello") { isLoading.toggle() } .buttonStyle(ProgressButtonStyle(isLoading: $isLoading)) } }
同时为该按钮的加载状态创建了自定义按钮样式:
struct ProgressButtonStyle: PrimitiveButtonStyle { @Binding var isLoading: Bool @Environment(\.isEnabled) var isEnabled func makeBody(configuration: PrimitiveButtonStyleConfiguration) -> some View { Button(action: { dispatchTrigger(configuration) }) { configuration .label .opacity(contentOpacity) } .buttonStyle(.base) .overlay(progressViewOverlay()) } @ViewBuilder func progressViewOverlay() -> some View { isLoading ? ProgressView().tint(progressTintColor) : nil } var progressTintColor: Color { if isEnabled { return .white } else { return Color(.tertiaryLabel) } } var contentOpacity: Double { isLoading ? 0.0 : 1.0 } private func dispatchTrigger(_ configuration: Configuration) { guard !isLoading else { return } configuration.trigger() } }
当通过其他按钮控制该按钮的显示状态时一切正常,但直接点击该按钮时,按钮文本会出现延迟消失的情况。
问题原因
自定义样式内部嵌套了Button,这个内部按钮会触发SwiftUI默认的点击动画,该动画会干扰文本opacity的即时变化,导致延迟消失的现象。
解决方案
移除自定义样式内部嵌套的Button,直接基于configuration.label构建视图,通过onTapGesture处理点击事件,避免默认动画的干扰:
struct ProgressButtonStyle: PrimitiveButtonStyle { @Binding var isLoading: Bool @Environment(\.isEnabled) var isEnabled func makeBody(configuration: Configuration) -> some View { configuration.label .opacity(contentOpacity) .overlay(progressViewOverlay()) .buttonStyle(.base) .onTapGesture { dispatchTrigger(configuration) } } @ViewBuilder func progressViewOverlay() -> some View { if isLoading { ProgressView().tint(progressTintColor) } } var progressTintColor: Color { isEnabled ? .white : Color(.tertiaryLabel) } var contentOpacity: Double { isLoading ? 0.0 : 1.0 } private func dispatchTrigger(_ configuration: Configuration) { guard !isLoading else { return } configuration.trigger() } }
替代方案(快速修复)
如果不想修改结构,也可以给文本的opacity变化添加明确的动画,覆盖默认动画的影响:
// 在原自定义样式的configuration.label处修改 configuration.label .opacity(contentOpacity) .animation(.easeOut(duration: 0.2), value: isLoading)
内容的提问来源于stack exchange,提问作者Betul Aksu
相关产品推荐
相关产品推荐

