如何让我的 Button 反映我的 EnvironmentObject 的 Bool?
How can I get my Button to reflect the Bool of my EnvironmentObject?
我正在尝试使用 @EnvironmentObject
来跟踪一些对象数组的 Bool 状态,但我遇到了一个超出范围的索引并且无法弄清楚原因。
我正在尝试跟踪在三个容器之间进行选择的“查询”。每个容器都有一定数量的“框架”,我需要切换这些框架并更改按钮标签的颜色:
import SwiftUI
class Query: ObservableObject {
@Published var selectedContainer: Int = 2
@Published var frames: [Bool] = [true, true, true, true, true, true, true, true]
func resetFrames() {
switch selectedContainer {
case 0:
self.frames = [true, true, true, true, true]
print("Boxes")
case 1:
self.frames = [true, true, true]
print("Bags")
case 2:
self.frames = [true, true, true, true, true, true, true, true]
print("Barrels")
default:
self.frames = [true, true, true]
}
}
func satisfiedFrames() {
let shouldReset = frames.allSatisfy { [=10=] == false }
print(shouldReset)
if shouldReset == true {
resetFrames()
}
}
}
enum Container {
case box
case bag
case barrel
var tag: Int {
switch self {
case .box:
return 0
case .bag:
return 1
case .barrel:
return 2
}
}
var name: String {
switch self {
case .box:
return "Box"
case .bag:
return "Bag"
case .barrel:
return "Barrel"
}
}
}
我也有我的颜色数组:
let dvColors: [Color] = [
Color.red,
Color.orange,
Color.yellow,
Color.green,
Color.blue,
Color.indigo,
Color.purple,
Color.pink
]
然后我有一个选择器可以像这样在容器之间切换:
@EnvironmentObject var query: Query
var container: [Container] = [.box, .bag, .barrel]
var body: some View {
Picker(selection: $query.selectedContainer, label: Text("Container")){
ForEach(0..<container.count) { index in
Text(self.container[index].name)
.tag(index)
}
}
.onChange(of: query.selectedContainer, perform: changeContainer)
}
func changeContainer(_ tag: Int) {
print("CHANGE CONTAINER ON PICKER")
print("TAG: \(tag)")
query.selectedContainer = tag
print("QUERY CONTAINER: \(query.selectedContainer)")
query.resetFrames()
print("FRAMES COUNT: \(query.frames.count)")
}
}
最后,这是我的内容视图:
import SwiftUI
struct ContentView: View {
@StateObject var query = Query()
var body: some View {
NavigationView {
ZStack {
ScrollView {
Text("FRAME COUNT: \(query.frames.count)")
Text("Container: \(query.selectedContainer)")
Spacer()
}
.navigationBarTitleDisplayMode(.inline)
.toolbar(){
ToolbarItem(placement: .principal, content: {
ContainerPicker()
})
}
VStack {
Spacer()
TheHStack()
}
}
}
.environmentObject(query)
}
}
struct TheHStack: View {
@EnvironmentObject var query: Query
var body: some View {
print(query.frames)
return HStack (spacing: 10) {
ForEach(query.frames.indices, id: \.self) { value in
ColouredText(value: value)
}
}
}
}
struct ColouredText: View {
@EnvironmentObject var query: Query
var value: Int
var body: some View {
Button(action: {
query.frames[value].toggle()
print(query.frames)
print("\(value)")
}, label: {
Text("\(value + 1)")
.foregroundColor(query.frames[value] ? dvColors[value] : .gray) // THIS LINE FAILS, I GUESS WHEN LOOKING UP THE COLOUR?
})
}
}
我希望做的是,当我使用选择器进行选择时,容器的布尔值都设置为 TRUE。然后点击按钮切换该容器中的框架。而当用picker选择另一个容器时,新容器的frame都是TRUE。此外,如果所有布尔值都变为 FALSE,则它们会自动重置为全部 TRUE。
如果我将三元色更改为一种颜色,一切正常。我的打印报表显示了正确的更改。但是我无法让 UI 正确更新。
方法一
您可以快速检查一下是否会出现越界错误。 SwiftUI 有时会保持视图的时间稍长,这可能会导致这样的问题。
在ColouredText
中,更改:
.foregroundColor(query.frames[value] ? dvColors[value] : .gray)
收件人:
.foregroundColor(value < query.frames.count && query.frames[value] ? dvColors[value] : .gray)
方法二
解决这个问题的另一种方法(但我可能不会这样做,因为你正在消除视图的分裂)是直接将 ColouredText
的 body
放在它所在的位置需要:
struct TheHStack: View {
@EnvironmentObject var query: Query
var body: some View {
print(query.frames)
return HStack (spacing: 10) {
ForEach(query.frames.indices, id: \.self) { value in
Button(action: {
query.frames[value].toggle()
print(query.frames)
print("\(value)")
}, label: {
Text("\(value + 1)")
.foregroundColor(query.frames[value] ? dvColors[value] : .gray)
})
}
}
}
}
方法三
您也可以通过在 value
的同时传入 query
来解决此问题。这意味着它们永远不会不同步。
ForEach(query.frames.indices, id: \.self) { value in
ColouredText(value: value, query: query)
}
struct ColouredText: View {
let value: Int
let query: Query
var body: some View {
/* ... */
}
}
我正在尝试使用 @EnvironmentObject
来跟踪一些对象数组的 Bool 状态,但我遇到了一个超出范围的索引并且无法弄清楚原因。
我正在尝试跟踪在三个容器之间进行选择的“查询”。每个容器都有一定数量的“框架”,我需要切换这些框架并更改按钮标签的颜色:
import SwiftUI
class Query: ObservableObject {
@Published var selectedContainer: Int = 2
@Published var frames: [Bool] = [true, true, true, true, true, true, true, true]
func resetFrames() {
switch selectedContainer {
case 0:
self.frames = [true, true, true, true, true]
print("Boxes")
case 1:
self.frames = [true, true, true]
print("Bags")
case 2:
self.frames = [true, true, true, true, true, true, true, true]
print("Barrels")
default:
self.frames = [true, true, true]
}
}
func satisfiedFrames() {
let shouldReset = frames.allSatisfy { [=10=] == false }
print(shouldReset)
if shouldReset == true {
resetFrames()
}
}
}
enum Container {
case box
case bag
case barrel
var tag: Int {
switch self {
case .box:
return 0
case .bag:
return 1
case .barrel:
return 2
}
}
var name: String {
switch self {
case .box:
return "Box"
case .bag:
return "Bag"
case .barrel:
return "Barrel"
}
}
}
我也有我的颜色数组:
let dvColors: [Color] = [
Color.red,
Color.orange,
Color.yellow,
Color.green,
Color.blue,
Color.indigo,
Color.purple,
Color.pink
]
然后我有一个选择器可以像这样在容器之间切换:
@EnvironmentObject var query: Query
var container: [Container] = [.box, .bag, .barrel]
var body: some View {
Picker(selection: $query.selectedContainer, label: Text("Container")){
ForEach(0..<container.count) { index in
Text(self.container[index].name)
.tag(index)
}
}
.onChange(of: query.selectedContainer, perform: changeContainer)
}
func changeContainer(_ tag: Int) {
print("CHANGE CONTAINER ON PICKER")
print("TAG: \(tag)")
query.selectedContainer = tag
print("QUERY CONTAINER: \(query.selectedContainer)")
query.resetFrames()
print("FRAMES COUNT: \(query.frames.count)")
}
}
最后,这是我的内容视图:
import SwiftUI
struct ContentView: View {
@StateObject var query = Query()
var body: some View {
NavigationView {
ZStack {
ScrollView {
Text("FRAME COUNT: \(query.frames.count)")
Text("Container: \(query.selectedContainer)")
Spacer()
}
.navigationBarTitleDisplayMode(.inline)
.toolbar(){
ToolbarItem(placement: .principal, content: {
ContainerPicker()
})
}
VStack {
Spacer()
TheHStack()
}
}
}
.environmentObject(query)
}
}
struct TheHStack: View {
@EnvironmentObject var query: Query
var body: some View {
print(query.frames)
return HStack (spacing: 10) {
ForEach(query.frames.indices, id: \.self) { value in
ColouredText(value: value)
}
}
}
}
struct ColouredText: View {
@EnvironmentObject var query: Query
var value: Int
var body: some View {
Button(action: {
query.frames[value].toggle()
print(query.frames)
print("\(value)")
}, label: {
Text("\(value + 1)")
.foregroundColor(query.frames[value] ? dvColors[value] : .gray) // THIS LINE FAILS, I GUESS WHEN LOOKING UP THE COLOUR?
})
}
}
我希望做的是,当我使用选择器进行选择时,容器的布尔值都设置为 TRUE。然后点击按钮切换该容器中的框架。而当用picker选择另一个容器时,新容器的frame都是TRUE。此外,如果所有布尔值都变为 FALSE,则它们会自动重置为全部 TRUE。
如果我将三元色更改为一种颜色,一切正常。我的打印报表显示了正确的更改。但是我无法让 UI 正确更新。
方法一
您可以快速检查一下是否会出现越界错误。 SwiftUI 有时会保持视图的时间稍长,这可能会导致这样的问题。
在ColouredText
中,更改:
.foregroundColor(query.frames[value] ? dvColors[value] : .gray)
收件人:
.foregroundColor(value < query.frames.count && query.frames[value] ? dvColors[value] : .gray)
方法二
解决这个问题的另一种方法(但我可能不会这样做,因为你正在消除视图的分裂)是直接将 ColouredText
的 body
放在它所在的位置需要:
struct TheHStack: View {
@EnvironmentObject var query: Query
var body: some View {
print(query.frames)
return HStack (spacing: 10) {
ForEach(query.frames.indices, id: \.self) { value in
Button(action: {
query.frames[value].toggle()
print(query.frames)
print("\(value)")
}, label: {
Text("\(value + 1)")
.foregroundColor(query.frames[value] ? dvColors[value] : .gray)
})
}
}
}
}
方法三
您也可以通过在 value
的同时传入 query
来解决此问题。这意味着它们永远不会不同步。
ForEach(query.frames.indices, id: \.self) { value in
ColouredText(value: value, query: query)
}
struct ColouredText: View {
let value: Int
let query: Query
var body: some View {
/* ... */
}
}