英文:
View row does not reflect correct value
问题
以下是您要翻译的内容:
"I am trying to display a list of items, each item having an index and a visibility flag. When I change the visibility of the item, and then move it down the list, the visibility of the item is not correctly reflected in the list.
To reproduce the issue 1) add 3 items by tapping on the +
button, 2) change visibility of PLOT 1
by tapping on the eye
icon, 3) tap the down icon on PLOT 1
swapping it with PLOT 2
. I am expecting that PLOT 1
will have visibility false and PLOT 2
will have visibility true, but instead they are reversed: PLOT 2
has visibility false, and PLOT 1
has visibility true, which is incorrect.
This code is running in macOS 13.0 app in Xcode 14.2 Swift 5"
以上内容已被翻译。
英文:
I am trying to display a list of items, each item having an index and a visibility flag. When I change the visibility of the item, and then move it down the list, the visibility of the item is not correctly reflected in the list.
To reproduce the issue 1) add 3 items by tapping on the +
button, 2) change visibility of PLOT 1
by tapping on the eye
icon, 3) tap the down icon on PLOT 1
swapping it with PLOT 2
. I am expecting that PLOT 1
will have visibility false and PLOT 2
will have visibility true, but instead they are reversed: PLOT 2
has visibility false, and PLOT 1
has visibility true, which is incorrect.
This code is running in macOS 13.0 app in Xcode 14.2 Swift 5
import SwiftUI
struct ContentView: View {
class Plot : Equatable {
static func == (lhs: ContentView.Plot, rhs: ContentView.Plot) -> Bool {
lhs === rhs
}
internal init(index: Int, visible: Bool = true) {
self.index = index
self.visible = visible
}
let index : Int
var visible : Bool = true
}
struct PlotView : View {
let plot : Plot
struct Delegate {
let moveDown : ()->Void
let canMoveDown : ()->Bool
}
let delegate : Delegate
@State private var visible = false
var body : some View {
HStack {
Text("PLOT \(plot.index)")
Button(action: {
visible.toggle()
}, label: {
Image(systemName: "eye.circle" + (visible ? ".fill" : ""))
})
Button(action: {
delegate.moveDown()
}, label: {
Image(systemName: "chevron.down.circle")
})
.disabled(!delegate.canMoveDown())
}
.onAppear {
visible = plot.visible
}
.onChange(of: visible) { v in
plot.visible = v
print("changed plot[\(plot.index)].visible = \(plot.visible ? "true" : "false")")
}
}
}
@State private var plots : [Plot] = []
var body: some View {
VStack {
ForEach(0..<plots.count, id: \.self) { i in
PlotView.init(plot: plots[i], delegate: .init(moveDown: {
if i < plots.count-1 {
plots.swapAt(i, i+1)
} else {
plots.insert(plots.removeLast(), at: 0)
}
}, canMoveDown: {
!plots.isEmpty
}))
}
Button(action: {
plots.append(.init(index: plots.count))
}, label: {
Image(systemName: "plus.circle")
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
答案1
得分: 1
I cannot say exactly why it doesn't work but it works with a Plot
struct and @Binding
Don't nest the things, it's bad practice.
This is Plot
, it became pretty tiny
struct Plot : Equatable, Identifiable {
let id = UUID()
let index : Int
var visible : Bool = true
}
Edit: In ContentView
the ForEach
expression iterates the element rather than the indices
struct ContentView: View {
@State private var plots : [Plot] = []
var body: some View {
VStack {
ForEach($plots) { $plot in
PlotView.init(plot: $plot, delegate: .init(moveDown: {
if let i = plots.firstIndex(of: plot),
i < plots.count-1 {
plots.swapAt(i, i+1)
} else {
plots.insert(plots.removeLast(), at: 0)
}
}, canMoveDown: {
!plots.isEmpty
}))
}
Button(action: {
plots.append(.init(index: plots.count))
}, label: {
Image(systemName: "plus.circle")
})
}
}
}
In Plotview
the Plot
instance is bound and the extra visible
property as well as the .onChange
modifier are not needed.
struct PlotView : View {
@Binding var plot : Plot
struct Delegate {
let moveDown : ()->Void
let canMoveDown : ()->Bool
}
let delegate : Delegate
var body : some View {
HStack {
Text("PLOT \(plot.index)")
Button(action: {
plot.visible.toggle()
}, label: {
Image(systemName: "eye.circle" + (plot.visible ? ".fill" : ""))
})
Button(action: {
delegate.moveDown()
}, label: {
Image(systemName: "chevron.down.circle")
})
.disabled(!delegate.canMoveDown())
}
}
}
英文:
I cannot say exactly why it doesn't work but it works with a Plot
struct and @Binding
Don't nest the things, it's bad practice.
This is Plot
, it became pretty tiny
struct Plot : Equatable, Identifiable {
let id = UUID()
let index : Int
var visible : Bool = true
}
Edit: In ContentView
the ForEach
expression iterates the element rather than the indices
struct ContentView: View {
@State private var plots : [Plot] = []
var body: some View {
VStack {
ForEach($plots) { $plot in
PlotView.init(plot: $plot, delegate: .init(moveDown: {
if let i = plots.firstIndex(of: plot),
i < plots.count-1 {
plots.swapAt(i, i+1)
} else {
plots.insert(plots.removeLast(), at: 0)
}
}, canMoveDown: {
!plots.isEmpty
}))
}
Button(action: {
plots.append(.init(index: plots.count))
}, label: {
Image(systemName: "plus.circle")
})
}
}
}
}
In Plotview
the Plot
instance is bound and the extra visible
property as well as the .onChange
modifier are not needed.
struct PlotView : View {
@Binding var plot : Plot
struct Delegate {
let moveDown : ()->Void
let canMoveDown : ()->Bool
}
let delegate : Delegate
var body : some View {
HStack {
Text("PLOT \(plot.index)")
Button(action: {
plot.visible.toggle()
}, label: {
Image(systemName: "eye.circle" + (plot.visible ? ".fill" : ""))
})
Button(action: {
delegate.moveDown()
}, label: {
Image(systemName: "chevron.down.circle")
})
.disabled(!delegate.canMoveDown())
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论