I have something like below, except I have additional dynamic gestures within "ChildContentView."
How would I force a child view to redraw/reload? Currently, any dynamic content draws once and does not reload. All content is essentially static.
Update: Needed to use let content: () -> Content
instead of @State var content: () -> Content
.
// ChildContentView
struct ChildContentView<Content: View>: View {
@State var content: () -> Content
var body: some View {
let dragGesture = DragGesture()...
return Group {
self.content()
}.gesture(dragGesture)
}
}
// ContentView
...
@State var changingList: [FooItem] = [] <-- This is dynamically changed. Not reflected in this code snippet.
var body: some View {
ZStack {
ChildContentView {
List(changingList) { item in
print("\(item)")
}
}
}
}
...
Your trouble is the State property wrapper
struct ChildContentView<Content: View>: View {
@State var content: () -> Content
var body: some View {
let dragGesture = DragGesture()...
return Group {
self.content()
}.gesture(dragGesture)
}
}
It makes the content "static" (actually you did it :-))
Let see and try this example (copy - paste - run in your simulator)
import SwiftUI
struct Child<Content: View>: View {
var content: () -> Content
var body: some View {
content()
}
}
struct Item: Identifiable {
let txt: String
let id = UUID()
}
struct ContentView: View {
@State var items = [Item(txt: "Alfa"), Item(txt: "Beta")]
var body: some View {
ZStack {
Child {
List(self.items) { (item) in
Text(item.txt)
}
}
Button(action: {
self.items.append(contentsOf: [Item(txt: "game"), Item(txt: "Delta")])
}) {
Text("Tap me to change items").padding().padding(.vertical, 50).background(Color.yellow)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Ensure that an item in the list modifies it's id
value when the content changes. Essentially hash the visual content to create a unique value per visual state.
eg
struct FooItem: Identifiable {
var id: UUID = UUID()
var text: String = ""
var visualID: String {
return id.uuidString
+ "\(text.hashValue)"
}
}
Im guessing that the internal ZStack
caching doesn't recognise that the object has changed when the id
doesn't change.
So using a ForEach
as that's what I've got in my code ( but List
has id
also )...
var body: some View {
ZStack {
ForEach(self.changingList, id: \.visualID) { item in
SomeView(item: item)
.onTapGesture {
//blah blah
}
}
}
}
I beat my head on this exact issue for days until working it out.
I am one month in to SwiftUI, so I don't fully understand why this works. However, setting the variable as a constant "let" passes the view content directly with updates.
Change from:
struct ChildContentView<Content: View>: View {
@State var content: () -> Content
var body: some View {
let dragGesture = DragGesture()...
return Group {
self.content()
}.gesture(dragGesture)
}
}
to this:
struct ChildContentView<Content: View>: View {
let content: () -> Content
var body: some View {
let dragGesture = DragGesture()...
return Group {
self.content()
}.gesture(dragGesture)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.