Post

Replies

Boosts

Views

Activity

SwiftUI ScrollView LazyVStack Performance
I am working with a ScrollView and a LazyVStack that can have many rows, sometimes 500 or more. My rows are expandable on tap. Performance of expand/collapse is unacceptable when the number of rows exceeds 100. The more rows, the more performance degrades. This is the gist of my code: struct PlaceView: View { 		/* ... */ 		var place: Place 		@Binding expandedPlaceId: Int 		var content: some View { 				VStack(alignment: .leading) { 						Text(place.name) 						 						if self.expandedPlaceId.wrappedValue == place.id { 								VStack(alignment: .leading) { 										Text(place.city) 								} 						} 				} 		} } struct PlacesListView: View { 		/*...*/ 		@State expandedPlaceId = -1 		var body: some View { 			ScrollView { 				LazyVStack { 					ForEach(places, id: \.id) { place in 						PlaceView(place: place, expandedPlaceId: self.$expandedPlaceId) 								.onTapGesture { self.selectDeselect(place) } 								.animation(.linear(duration: 0.3)) 					} 			 } 		 } 	} } I created an init function in PlaceView with the following: print("calling int for place \(place.id)") What I have noticed is when expanding, every single PlaceView calls init. For 20 or 30 PlaceView rows this is not a problem, but with several hundred views this creates a choppiness in animation and delays the expansion of the detail section. Is there any workaround for this problem? It does not matter if I use LazyVStack or VStack (which itself is unexpected). Here is an example project that can easily be modified to highlight the problem: https://github.com/V8tr/ExpandableListSwiftUI In the above project, simply add the following to PlaceView.swift init(place: Place, isExpanded: Bool) {         self.place = place         self.isExpanded = isExpanded         print("PlaceView init \(self.place.id)") }
2
1
4.5k
Aug ’20
How to safely use ScrollViewProxy scrollTo
When using ScrollViewProxy scrollTo, if a "row" the VStack/LazyVStack is expandable and is expanding, it will randomly result in a crash: [error] precondition failure: setting value during update: 4927752 AttributeGraph precondition failure: setting value during update: 4927752. Is there a safe way to use scrollTo in such that this does not occur?
1
0
841
Aug ’20
NavigationLink goes forwards then backwards
I am programmatically directing traffic in my app using NavigationLink and isActive. My primary hierarchy goes like this ContentView -> View 2 -> View 3. And then ContentView -> View 4 (but this part doesn't work). What I would like to do is pop back to the root ContentView from anywhere and then navigate to a fourth view. Popping back to root is easy, navigating to that fourth view programmatically seems impossible due to a bug in NavigationLink where the fourth view will become active and visible only to immediately go back to ContentView. Here is my code: import SwiftUI @main struct BugApp: App { @StateObject var session = Session() var body: some Scene { WindowGroup { ContentView() .environmentObject(session) } } } class Session: ObservableObject { @Published var showingContentViewTwo: Bool = false @Published var showContentViewFour: Bool = false } struct ContentView: View { @EnvironmentObject var session: Session @State private var showingContentViewFour = false var body: some View { NavigationView { VStack { Spacer() NavigationLink(destination: ContentViewTwo(), isActive: $session.showingContentViewTwo) { EmptyView() }.isDetailLink(false) NavigationLink(destination: ContentViewFour(), isActive: self.$showingContentViewFour) { EmptyView() }.isDetailLink(false) Text("I am ContentView") .padding() HStack { HStack(alignment: .center) { Spacer() Text("Go To View 2") .foregroundColor(Color.primary) .bold() Spacer() }.padding() .background(Color.blue) } .padding() .onTapGesture(count: 1) { session.showingContentViewTwo = true } .onReceive(session.$showContentViewFour) { value in if value { session.showContentViewFour = false self.showingContentViewFour = true } } Spacer() } } } } struct ContentViewTwo: View { @EnvironmentObject var session: Session var body: some View { VStack { Spacer() Text("I am ContentViewTwo") .padding() NavigationLink(destination: ContentViewThree()) { HStack { HStack(alignment: .center) { Spacer() Text("Go To View 3") .foregroundColor(Color.primary) .bold() Spacer() }.padding() .background(Color.blue) } } .padding() Spacer() } } } struct ContentViewThree: View { @EnvironmentObject var session: Session @State private var showingViewFour: Bool = false var body: some View { VStack { NavigationLink(destination: ContentViewFour(), isActive: self.$showingViewFour) { EmptyView() }.isDetailLink(false).hidden().allowsHitTesting(false) Spacer() Text("I am ContentViewThree") .padding() Button(action: { session.showingContentViewTwo = false session.showContentViewFour = true }) { HStack { HStack(alignment: .center) { Spacer() Text("Go All The Way Back") .foregroundColor(Color.primary) .bold() Spacer() }.padding() .background(Color.blue) } } .padding() Spacer() } } } struct ContentViewFour: View { @Environment(\.presentationMode) var presentationMode @EnvironmentObject var session: Session var body: some View { VStack { Spacer() Text("I am ContentViewFour") .padding() Button(action: { self.presentationMode.wrappedValue.dismiss() }) { HStack { HStack(alignment: .center) { Spacer() Text("Go Back") .foregroundColor(Color.primary) .bold() Spacer() }.padding() .background(Color.green) } } .padding() Spacer() } } } Help?
1
0
1.1k
Jun ’21