Let's say I have an array that I am appending first with one element in another view, and then appending with the second element from the third view. How to return to the starting view and deduce two additional views from memory?
struct ContentView: View {
@State var array: [String] = []
var body: some View {
NavigationView{
ScrollView{
ForEach(array, id: \.self) { element in
Text(element)
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink("+") {
Details(array: $array)
}
}
}
}
}
}
struct Details: View {
@Binding var array: [String]
var body: some View {
Button(action: { array.append("First Element") }) {
Text("Append First Element")
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink("+") {
}
}
}
}
}
struct MoreDetails: View {
@Binding var array: [String]
@Environment(\.dismiss) var dismiss
var body: some View {
Button(action: { array.append("Second Element") }) {
Text("Append Second Element")
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink("Done") {
ContentView(array: array)
}
.simultaneousGesture(TapGesture().onEnded{
dismiss()
})
}
}
}
}
The issue you are having really is one of navigation, or at least how you think you want to navigate. What you have set up in terms of navigation is this:
Original ContentView -> Details -> MoreDetails -> New ContentView
When what you wanted was:
Original ContentView -> Details -> MoreDetails -> Original ContentView
without having to navigate back through all of the views. To do this, essentially you build a house of cards and then pull the bottom card out, and your navigation collapses back to the original ContentView
. Commented code:
struct ContentView: View {
@State var array: [String] = []
// originalIsActive is your bottom card, and you will carry a reference
// through your views like a piece of twine.
@State var originalIsActive = false
var body: some View {
NavigationView{
ScrollView{
ForEach(array, id: \.self) { element in
Text(element)
}
}
.background(
// This is a programatic NavigationLink that triggers when originalIsActive
// becomes true. Placed in a background it sits and listens for originalIsActive.
NavigationLink(isActive: $originalIsActive, destination: {
Details(array: $array, originalIsActive: $originalIsActive)
}, label: {
// This is simply a nothing view, so you can't see the NavigationLink.
EmptyView()
})
// Necessary to prevent link pop back after this NavigationLink
.isDetailLink(false)
)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
// This Button sets originalIsActive to true, activating the NavigationLink.
originalIsActive = true
} label: {
Image(systemName: "plus")
}
}
}
}
}
}
struct Details: View {
@Binding var array: [String]
// Reference to originalIsActive
@Binding var originalIsActive: Bool
@State var detailsIsActive = false
var body: some View {
Button(action: { array.append("First Element") }) {
Text("Append First Element")
}
.background(
NavigationLink(isActive: $detailsIsActive, destination: {
MoreDetails(array: $array, originalIsActive: $originalIsActive)
}, label: {
EmptyView()
})
// Necessary to prevent link pop back after this NavigationLink
.isDetailLink(false)
)
.toolbar {
Button {
detailsIsActive = true
} label: {
Image(systemName: "plus")
}
}
}
}
struct MoreDetails: View {
@Binding var array: [String]
// Reference to originalIsActive
@Binding var originalIsActive: Bool
var body: some View {
Button(action: { array.append("Second Element") }) {
Text("Append Second Element")
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
// By setting originalIsActive to false, you pull out the bottom card.
// If the first link does not exist, none do.
originalIsActive = false
} label: {
Text("Original")
}
}
}
}
}