UISegmentedControl 在状态改变时不改变

问题描述

下面是我的选择器的代码

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
        }
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...