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?
Post
Replies
Boosts
Views
Activity
Use of contextMenu randomly causes the following crash/error:
CoreSimulator 732.13 - Device: iPhone 11 Pro Max (7932F9B5-D9B7-4365-B442-78A1D7718034) - Runtime: iOS 14.0 (18A5357e) - DeviceType: iPhone 11 Pro Max
AttributeGraph precondition failure: setting value during update: 4216072.
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?
Using recursive views, even with each subview housing a single container VStack and .id(), scrollTo does not function. There are no duplicate ids, scrollTo simply does nothing.
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)")
}
As of Xcode 12 beta 3, WKWebView content is no longer visible in the simulator.