让 SwiftUI Picker() 选择更新应用程序状态更改的最佳方法是什么?
Whats the best way to get SwiftUI Picker() selection to update on app state change?
我正在尝试使用 SwiftUI 制作一个 UI,它列出了可以是不同种类并且每个都可以更新的事物的集合。我想使用 Picker 在 UI 中设置类型,并且我还希望在以其他方式修改项目时更新视图(例如,从 UI 的另一部分,或通过网络。)
我喜欢“redux”风格的设置,我不想放弃它。
这是一个显示两个项目的简单示例,每个项目都有一个随机更改项目的“随机化”按钮和一个让您选择新项目类型的选择器。后者按预期工作:Picker
更改 @State var
,商店更新等。'randomize' 按钮更新商店和 let
属性 标签, 但 @State
和 Picker
不更新。
我希望得到一些关于如何让它按照我想要的方式工作的好方法的建议。
import SwiftUI
import Combine
@main
struct PuffedWastApp: App {
var store = Store()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(store)
}
}
}
enum ItemState:String, CaseIterable {
case apple
case bannana
case coconut
}
enum Action {
case set(Int,ItemState)
}
class Store: ObservableObject {
@Published var state:[ItemState] = [.apple, .apple]
func reduce(_ action:Action) {
print("do an action")
switch (action) {
case let .set(index,new_state):
print("set \(index) to \(new_state)")
state[index] = new_state
self.objectWillChange.send()
}
}
}
struct ContentView: View {
@EnvironmentObject var store: Store
var body: some View {
VStack {
ForEach(store.state.indices) { index in
ItemContainer(index: index)
//Text("\(index)")
}
}
.padding()
}
}
struct ItemContainer: View {
@EnvironmentObject var store: Store
let index: Int
var body: some View {
ItemView(
index: index,
label: store.state[index], // let property: updates on change in the Store
localLabel: store.state[index], //@State variable; doesn't update on change in the Store
dispatch: store.reduce
)
.padding()
}
}
struct ItemView: View {
let index: Int
let label: ItemState
@State var localLabel: ItemState
let dispatch: (Action)->()
var body: some View {
HStack{
//Text("\(index)")
Text(label.rawValue)
Text(localLabel.rawValue)
Button("Randomize") { dispatch( .set(index, ItemState.allCases.randomElement() ?? .apple ) ) }
Picker("Item type", selection: $localLabel ) {
ForEach( ItemState.allCases , id: \.self ) {
Text([=10=].rawValue).tag([=10=])
}
}.onChange(of: localLabel) { dispatch(.set(index, [=10=])) }
}
.padding()
}
}
尝试更改此行:
@State var localLabel: ItemState
到
@Binding var localLabel: ItemState
并将其传递到您的 ItemView
init 中:
ItemView(
index: index,
label: store.state[index],
localLabel: $store.state[index],
dispatch: store.reduce
)
我正在尝试使用 SwiftUI 制作一个 UI,它列出了可以是不同种类并且每个都可以更新的事物的集合。我想使用 Picker 在 UI 中设置类型,并且我还希望在以其他方式修改项目时更新视图(例如,从 UI 的另一部分,或通过网络。)
我喜欢“redux”风格的设置,我不想放弃它。
这是一个显示两个项目的简单示例,每个项目都有一个随机更改项目的“随机化”按钮和一个让您选择新项目类型的选择器。后者按预期工作:Picker
更改 @State var
,商店更新等。'randomize' 按钮更新商店和 let
属性 标签, 但 @State
和 Picker
不更新。
我希望得到一些关于如何让它按照我想要的方式工作的好方法的建议。
import SwiftUI
import Combine
@main
struct PuffedWastApp: App {
var store = Store()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(store)
}
}
}
enum ItemState:String, CaseIterable {
case apple
case bannana
case coconut
}
enum Action {
case set(Int,ItemState)
}
class Store: ObservableObject {
@Published var state:[ItemState] = [.apple, .apple]
func reduce(_ action:Action) {
print("do an action")
switch (action) {
case let .set(index,new_state):
print("set \(index) to \(new_state)")
state[index] = new_state
self.objectWillChange.send()
}
}
}
struct ContentView: View {
@EnvironmentObject var store: Store
var body: some View {
VStack {
ForEach(store.state.indices) { index in
ItemContainer(index: index)
//Text("\(index)")
}
}
.padding()
}
}
struct ItemContainer: View {
@EnvironmentObject var store: Store
let index: Int
var body: some View {
ItemView(
index: index,
label: store.state[index], // let property: updates on change in the Store
localLabel: store.state[index], //@State variable; doesn't update on change in the Store
dispatch: store.reduce
)
.padding()
}
}
struct ItemView: View {
let index: Int
let label: ItemState
@State var localLabel: ItemState
let dispatch: (Action)->()
var body: some View {
HStack{
//Text("\(index)")
Text(label.rawValue)
Text(localLabel.rawValue)
Button("Randomize") { dispatch( .set(index, ItemState.allCases.randomElement() ?? .apple ) ) }
Picker("Item type", selection: $localLabel ) {
ForEach( ItemState.allCases , id: \.self ) {
Text([=10=].rawValue).tag([=10=])
}
}.onChange(of: localLabel) { dispatch(.set(index, [=10=])) }
}
.padding()
}
}
尝试更改此行:
@State var localLabel: ItemState
到
@Binding var localLabel: ItemState
并将其传递到您的 ItemView
init 中:
ItemView(
index: index,
label: store.state[index],
localLabel: $store.state[index],
dispatch: store.reduce
)