问题描述
下面是我的选择器的代码:
struct pickerSwitch: View {
@Observedobject var appState: AppState
@State var selection: String = "Red"
var colors = ["Red","Blue"]
init(appState: AppState) {
print("Init ran again")
self.appState = appState
if appState.showBlueControl {
UISegmentedControl.appearance().setTitleTextAttributes([.font : UIFont.preferredFont(forTextStyle: .headline)],for: .normal)
UISegmentedControl.appearance().backgroundColor = .blue
} else {
UISegmentedControl.appearance().setTitleTextAttributes([.font : UIFont.preferredFont(forTextStyle: .headline)],for: .normal)
UISegmentedControl.appearance().backgroundColor = .red
}
}
var body: some View {
Picker(selection: $selection,label: Text("")) {
ForEach(colors,id: \.self) {
Text($0)
}
}.pickerStyle(SegmentedPickerStyle())
}
}
在我的代码的其他地方,我有一个按钮可以更改“AppState”的特定实例的“showBlueControl”的值。在我的 Xcode 日志中,我看到很多“Init running again”日志,所以我认为分段控件应该发生变化,但由于某种原因,只有在我完全关闭视图并重新打开它时才会发生变化。当 SwiftUI 状态发生变化(不关闭/重新打开视图)时,如何动态更改 SegmentedControl?
解决方法
您只需要一个 @State
来跟踪背景颜色。然后在选择器上设置 .background()
。要更改您的状态变量,只需使用 .onChange
。
struct PickerSwitch: View {
@State var selection: String = "Red"
var colors = ["Red","Blue"]
@State var backgroundColor = Color.red // This tracks your background color
var body: some View {
Picker(selection: $selection,label: Text("")) {
ForEach(colors,id: \.self) {
Text($0)
}
}
// .onChange reacts to the change of selection
.onChange(of: selection,perform: { value in
if value == "Red" {
backgroundColor = .red
} else {
backgroundColor = .blue
}
})
.pickerStyle(SegmentedPickerStyle())
.background(backgroundColor) // Set your background color here
}
}
,
您可以使用 SwiftUI-Introspect。我更喜欢这个而不是改变视图的 .id(_:)
,因为:
当您更改视图的 ID 时,您会导致它失效并因此重新创建。它还可能导致一些奇怪的错误,例如动画奇怪地停止,无法在中途更改选项卡以中断动画。但是,使用 Introspect,视图不会重新初始化。视图主体会在 appState
更改时更新。
此外,使用 Introspect 时,样式只会影响这一个 Picker
- 而不是整个应用程序中的每一个。
我还简化了您处理跟踪颜色的方式。请注意,我们使用 $appState.switchColor
绑定到所选颜色。
代码:
struct ContentView: View {
@StateObject private var appState = AppState()
var body: some View {
PickerSwitch(appState: appState)
}
}
enum SwitchColor: String,CaseIterable,Identifiable {
case red = "Red"
case blue = "Blue"
var id: String { rawValue }
var color: UIColor {
switch self {
case .red: return .red
case .blue: return .blue
}
}
}
class AppState: ObservableObject {
@Published var switchColor: SwitchColor = .red
}
struct PickerSwitch: View {
@ObservedObject var appState: AppState
var body: some View {
Picker("Select color",selection: $appState.switchColor) {
ForEach(SwitchColor.allCases) { color in
Text(color.rawValue).tag(color)
}
}
.pickerStyle(.segmented)
.introspectSegmentedControl { segmentedControl in
let attributes = [NSAttributedString.Key.font : UIFont.preferredFont(forTextStyle: .headline)]
segmentedControl.setTitleTextAttributes(attributes,for: .normal)
segmentedControl.backgroundColor = appState.switchColor.color
}
}
}