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

SwiftUI中如何动态更新自定义ButtonStyle?

解决SwiftUI自定义ButtonStyle不响应状态更新的问题

问题根源

你在TestButton里错误地使用了@State来存储selected属性。@State是用来管理View内部私有状态的,而ButtonStyle是一个样式结构体,它本身不是View,不需要用@State维持状态。当外部传入的selected参数变化时,@State会“持有”初始值,导致ButtonStyle无法响应外部状态的更新。

正确方案

直接移除TestButton中的@State修饰符,将selected改为普通属性接收外部值:

struct TestButton: ButtonStyle {
    // 移除@State,改为普通属性接收外部传入的选中状态
    var selected: Bool = true
    
    func makeBody(configuration: ButtonStyleConfiguration) -> some View {
        configuration.label
            .frame(width: 48)
            .padding(EdgeInsets(top: 3, leading: 4, bottom: 3, trailing: 4))
            .background(selected ? .green : .red)
            .cornerRadius(14)
    }
}

struct TestView: View {
    @AppStorage("test") var test = 1
    
    var body: some View {
        HStack {
            Button(test == 1 ? "Yes" : "No") { test = 1 }
                .buttonStyle(TestButton(selected: test == 1))
            Button(test == 2 ? "Yes" : "No") { test = 2 }
                .buttonStyle(TestButton(selected: test == 2))
            Button(test == 3 ? "Yes" : "No") { test = 3 }
                .buttonStyle(TestButton(selected: test == 3))
        }
        .padding()
    }
}

原理说明

ButtonStyle的makeBody方法会随着传入参数的变化自动重新执行。当test的值改变时,传入TestButton的selected参数会同步更新,此时ButtonStyle会重新生成按钮的布局,从而正确切换背景颜色。

为什么.id(UUID())能生效但不推荐

给HStack添加.id(UUID())会强制整个视图树重新创建,TestButton会被重新初始化,自然能获取到新的selected值。但这种方式会导致整个HStack及其子视图被完全重建,带来不必要的性能开销,因此不是最优解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:50:13