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
相关产品推荐
相关产品推荐

