遍历数组中视图(结构)的属性返回错误的值(初始值)
Looping over the properties of Views (struct) in an Array is returning wrong values (init values)
我正在使用一组标签视图来显示带有所有标签的滚动视图。当这些标签被点击时,它们被选中并且标签视图中的 @State
布尔值 属性 被切换。因此在底部单击“提交”按钮时,选定 标签的值将发送到服务器。
在“提交”按钮中,我使用 For-Loop 循环遍历标签视图并检查具有 myLabel.isSelected == true
的标签,但即使在之后所有标签都返回 false
被选中。
主视图简化:
struct Sheet: View {
@State var myLabels: [MyLabel] = [
MyLabel(systemImage: "sparkles", text: "Keine Gebrauchsspuren"),
MyLabel(systemImage: "checkmark.circle", text: "Minimale Gebrauchsspuren"),
MyLabel(systemImage: "exclamationmark.circle", text: "Mehrere Gebrauchsspuren"),
MyLabel(systemImage: "xmark.circle", text: "Starke Gebrauchsspuren"),
MyLabel(systemImage: "arrow.down.to.line", text: "Delle(n)")
]
var body: some View {
ScrollView {
ForEach(myLabels, id: \.self) {label in label}
}
Button {
var combinedString = ""
for label in myLabels {
if label.isSelected {
combinedString += label.text
}
}
postTextFunc(combinedString)
} label: {
Text("Submit")
}
}
combinedString
总是返回空,因为当我遍历 myLabels
时,所有标签都将 isSelected
设置为 false
。这是因为 SwiftUI 在属性更改时如何处理结构吗?我怎样才能达到我的目标,即只返回提示标签的值?
非常感谢!
视图是 SwiftUI 中的结构。因此将它们传递给函数将创建这些视图的副本。而你正在迭代未修改的原始视图。
我认为 ViewModel/Model 在这里最好。
struct Model: Identifiable{
var selected: Bool
let text: String
let id = UUID()
}
class Viewmodel: ObservableObject{
@Published var models: [Model] = [] //Create the datamodel here
func select(_ selectedModel: Model){
var selectedModel = selectedModel
selectedModel.selected.toggle() //Create a new copy and toggle selection
// get index of selected item
guard let index = models.firstIndex(where: {[=10=].id == selectedModel.id}) else{
return
}
// assign item. This will toggle changes in the view
models[index] = selectedModel
}
func post(){
//Create combined string
let combinedString = models.filter{[=10=].selected}.reduce("") { partialResult, model in
partialResult + model.text
}
//call post
postTextFunc(combinedString)
}
func postTextFunc(_ string: String){
}
}
struct InnerView: View{
@EnvironmentObject private var viewmodel: Viewmodel
var selected: Model // provide the individual data here
var body: some View{
Text(selected.text)
.onTapGesture {
viewmodel.select(selected)
}
}
}
struct TestView: View{
@StateObject private var viewmodel = Viewmodel()
var body: some View {
ScrollView {
ForEach(viewmodel.models, id: \.id) { model in
InnerView(selected: model)
.environmentObject(viewmodel) // pass viewmodel in environment
}
}
Button {
viewmodel.post()
} label: {
Text("Submit")
}
}
}
我正在使用一组标签视图来显示带有所有标签的滚动视图。当这些标签被点击时,它们被选中并且标签视图中的 @State
布尔值 属性 被切换。因此在底部单击“提交”按钮时,选定 标签的值将发送到服务器。
在“提交”按钮中,我使用 For-Loop 循环遍历标签视图并检查具有 myLabel.isSelected == true
的标签,但即使在之后所有标签都返回 false
被选中。
主视图简化:
struct Sheet: View {
@State var myLabels: [MyLabel] = [
MyLabel(systemImage: "sparkles", text: "Keine Gebrauchsspuren"),
MyLabel(systemImage: "checkmark.circle", text: "Minimale Gebrauchsspuren"),
MyLabel(systemImage: "exclamationmark.circle", text: "Mehrere Gebrauchsspuren"),
MyLabel(systemImage: "xmark.circle", text: "Starke Gebrauchsspuren"),
MyLabel(systemImage: "arrow.down.to.line", text: "Delle(n)")
]
var body: some View {
ScrollView {
ForEach(myLabels, id: \.self) {label in label}
}
Button {
var combinedString = ""
for label in myLabels {
if label.isSelected {
combinedString += label.text
}
}
postTextFunc(combinedString)
} label: {
Text("Submit")
}
}
combinedString
总是返回空,因为当我遍历 myLabels
时,所有标签都将 isSelected
设置为 false
。这是因为 SwiftUI 在属性更改时如何处理结构吗?我怎样才能达到我的目标,即只返回提示标签的值?
非常感谢!
视图是 SwiftUI 中的结构。因此将它们传递给函数将创建这些视图的副本。而你正在迭代未修改的原始视图。
我认为 ViewModel/Model 在这里最好。
struct Model: Identifiable{
var selected: Bool
let text: String
let id = UUID()
}
class Viewmodel: ObservableObject{
@Published var models: [Model] = [] //Create the datamodel here
func select(_ selectedModel: Model){
var selectedModel = selectedModel
selectedModel.selected.toggle() //Create a new copy and toggle selection
// get index of selected item
guard let index = models.firstIndex(where: {[=10=].id == selectedModel.id}) else{
return
}
// assign item. This will toggle changes in the view
models[index] = selectedModel
}
func post(){
//Create combined string
let combinedString = models.filter{[=10=].selected}.reduce("") { partialResult, model in
partialResult + model.text
}
//call post
postTextFunc(combinedString)
}
func postTextFunc(_ string: String){
}
}
struct InnerView: View{
@EnvironmentObject private var viewmodel: Viewmodel
var selected: Model // provide the individual data here
var body: some View{
Text(selected.text)
.onTapGesture {
viewmodel.select(selected)
}
}
}
struct TestView: View{
@StateObject private var viewmodel = Viewmodel()
var body: some View {
ScrollView {
ForEach(viewmodel.models, id: \.id) { model in
InnerView(selected: model)
.environmentObject(viewmodel) // pass viewmodel in environment
}
}
Button {
viewmodel.post()
} label: {
Text("Submit")
}
}
}