How do I transition between views while controlling which view I transition from

I am trying to teach myself transitions with animations. I have code that does all that I want with one exception. The code consists of a navigation view with two selectable items on the navigation side. Each item controls which of two associated views is displayed, a data view and a graph view, for a total of four views. When selecting a single item I get a nice slide transition between the two views. But when I select the other item the transition goes from the graph view for that item to the data view for that item. What I would like is for the data view for the selected item to always be the first view shown and the transition be from what ever view was last selected from the other item, if that all makes sense. Any assistance in pointing me in the right direction will be appreciated. Below is the code:

import SwiftUI

struct ContentView: View {
    
    @State private var showVGraph: Bool = false
    @State private var showVFGraph: Bool = false
    @State private var currentSelection: Int = 1
    
    var body: some View {
        
        NavigationView {
            
            SideView(currentSelection: $currentSelection, showVGraph: $showVGraph, showVFGraph: $showVFGraph)
            
            VStack{
                if currentSelection == 1 {
                    if !showVGraph {
                        DataV()
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                            .background(Color.blue)
                            .transition(AnyTransition.slide)
                    }
                    if showVGraph {
                        GraphV()
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                            .background(Color.green)
                            .transition(AnyTransition.slide)
                    }
                }
                if currentSelection == 2 {
                    if !showVFGraph {
                        DataVF()
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                            .background(Color.gray)
                            .transition(AnyTransition.slide)
                    }
                    if showVFGraph {
                        GraphVF()
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                            .background(Color.indigo)
                            .transition(AnyTransition.slide)
                    }
                }
            }
        }.frame(width: 900, height: 600)
    }
}

struct SideView: View {
    
    @Binding var currentSelection: Int
    @Binding var showVGraph: Bool
    @Binding var showVFGraph: Bool
    @State var button1Text: String = "1 Data / Graph"
    @State var button2Text: String = "2 Data / Graph"
    
    var body: some View {
        
        Spacer().frame(height: 60)
        SideViewText(item: 1, currentSelection: $currentSelection, showVGraph: $showVGraph, showVFGraph: $showVFGraph, button1Text: $button1Text, button2Text: $button2Text)
        Spacer().frame(height: 20.0)
        SideViewText(item: 2, currentSelection: $currentSelection, showVGraph: $showVGraph, showVFGraph: $showVFGraph, button1Text: $button1Text, button2Text: $button2Text)
        Spacer()
        
    } // end body
} // end view

struct SideViewText: View {
    
    var item: Int
    @Binding var currentSelection: Int
    @Binding var showVGraph: Bool
    @Binding var showVFGraph: Bool
    @Binding  var button1Text: String
    @Binding var  button2Text: String
    
    var body: some View {
        
        switch item {
        case 1:
            Text (self.button1Text)
                .font(.system(size: 15))
                .underline()
                .foregroundColor(Color.blue)
                .onTapGesture {
                    self.showVFGraph = true
                    currentSelection = item
                    withAnimation(.easeIn(duration: 0.2)) {
                        self.showVGraph.toggle()
                    }
                    if !showVGraph {
                        self.button1Text = "1 Data / Graph"
                    } else {
                        self.button1Text = "1 Graph / Data"
                    }
                    button2Text = "2 Data / Graph"
                }
        default:
            Text (self.button2Text)
                .font(.system(size: 15))
                .underline()
                .foregroundColor(Color.blue)
                .onTapGesture {
                    self.showVGraph = true
                    currentSelection = item
                    withAnimation(.easeIn(duration: 0.2)) {
                        self.showVFGraph.toggle()
                    }
                    if !showVFGraph {
                        self.button2Text = "2 Data / Graph"
                    } else {
                        self.button2Text = "2 Graph / Data"
                    }
                    button1Text = "1 Data / Graph"
              }
        }
    } // end of var body
}

struct DataV: View {
    var body: some View {
        Text("Data V").font(.title)
    }
}

struct GraphV: View {
    var body: some View {
        Text("Graph V").font(.title)
    }
}

struct DataVF: View {
    var body: some View {
        Text("Data VF").font(.title)
    }
}

struct GraphVF: View {
    var body: some View {
        Text("Graph VF").font(.title)
    }
}

After some research I decided that I could solve the problem by using a ZStack vs a VStack and to change the transition. I went from a slide to a move/edge and then made the edge value a variable I could programmatically change between leading and trailing. In addition, I changed the animation to easeInOut from easeIn with a duration. It requires that I consider every option which requires a lot of code but it works as desired. Below is my code less the view model and model that I created to reduce the amount of data I was having to pass between structures. I should have done more research before making my initial post.

struct ContentView: View {
    
    @EnvironmentObject var navVM: NavigationViewModel
    
    var body: some View {
        
        NavigationView {
            NavigationList()
            ZStack {
                if navVM.showHome {
                    Home()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color.blue)
                        .transition(AnyTransition.move(edge: navVM.homeTransition))
                }
                if navVM.showVData {
                    DataV()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color.green)
                        .transition(AnyTransition.move(edge: navVM.dataVTransition))
                } // end if
                if navVM.showVGraph {
                    GraphV()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color.gray)
                        .transition(AnyTransition.move(edge: navVM.graphVTransition))
                } // end if
            } // end zStack
        } .frame(width: 900, height: 600) // navigation view
    }
}

struct NavigationList: View {
    
    @EnvironmentObject var navVM: NavigationViewModel
    
    var body: some View {
        
        Text (navVM.button1Text)
            .font(.system(size: 15))
            .underline()
            .foregroundColor(Color.blue)
            .onTapGesture {
                navVM.SetPreviousSelection(value: navVM.currentSelection)
                navVM.SetCurrentSelection(value: 1)
                if navVM.previousSelection == 2 {
                    navVM.SetShowHome(value: false)
                    navVM.SetHomeTransition(value: .leading)
                    navVM.SetDataVTransition(value: .trailing)
                    withAnimation(.easeInOut) {
                        navVM.SetShowHome(value: true)
                    }
                    withAnimation(.easeInOut) {
                        navVM.SetShowVData(value: false)
                    }
                    navVM.SetButton2Text(value: "VData / VGraph")
                }
                if navVM.previousSelection == 3 {
                    navVM.SetShowVData(value: false)
                    navVM.SetHomeTransition(value: .leading)
                    navVM.SetGraphVTransition(value: .trailing)
                    withAnimation(.easeInOut) {
                        navVM.SetShowHome(value: true)
                    }
                    withAnimation(.easeInOut) {
                        navVM.SetShowVGraph(value: false)
                    }
                    navVM.SetButton2Text(value: "VData / VGraph")
                }
            }
        Spacer().frame(height: 20)
        
        Text (navVM.button2Text)
            .font(.system(size: 15))
            .underline()
            .foregroundColor(Color.blue)
            .onTapGesture {
                navVM.SetPreviousSelection(value: navVM.currentSelection)
                if navVM.currentSelection == 2 {
                    navVM.SetCurrentSelection(value: 3)
                } else {
                    navVM.SetCurrentSelection(value: 2)
                }
                if navVM.currentSelection == 2 && navVM.previousSelection == 1 {
                    navVM.SetShowVGraph(value: false)
                    navVM.SetHomeTransition(value: .trailing)
                    navVM.SetDataVTransition(value: .leading)
                    withAnimation(.easeInOut) {
                        navVM.SetShowHome(value: false)
                    }
                    withAnimation(.easeInOut) {
                        navVM.SetShowVData(value: true)
                    }
                    navVM.SetButton2Text(value: "VData / VGraph")
                } // end if
                if navVM.currentSelection == 3 && navVM.previousSelection == 1 {
                    navVM.SetShowVData(value: false)
                    navVM.SetHomeTransition(value: .trailing)
                    navVM.SetGraphVTransition(value: .leading)
                    withAnimation(.easeInOut) {
                        navVM.SetShowHome(value: false)
                    }
                    withAnimation(.easeInOut) {
                        navVM.SetShowVGraph(value: true)
                    }
                    navVM.SetButton2Text(value: "VGraph / VData")
                } // end if
                if navVM.currentSelection == 3 && navVM.previousSelection == 2 {
                    navVM.SetShowHome(value: false)
                    navVM.SetDataVTransition(value: .trailing)
                    navVM.SetGraphVTransition(value: .leading)
                    withAnimation(.easeInOut) {
                        navVM.SetShowVData(value: false)
                    }
                    withAnimation(.easeInOut) {
                        navVM.SetShowVGraph(value: true)
                    }
                    navVM.SetButton2Text(value: "VGraph / VData")
                } // end if
                if navVM.currentSelection == 2 && navVM.previousSelection == 3 {
                    navVM.SetShowHome(value: false)
                    navVM.SetDataVTransition(value: .leading)
                    navVM.SetGraphVTransition(value: .trailing)
                    withAnimation(.easeInOut) {
                        navVM.SetShowVData(value: true)
                    }
                    withAnimation(.easeInOut) {
                        navVM.SetShowVGraph(value: false)
                    }
                    navVM.SetButton2Text(value: "VData / VGraph")
                }
            }
    }  // end body
} // end view

struct PlaceHolder: View {
    
    var body: some View {
        Text("PlaceHolder").font(.title)
    }
}

struct Home: View {
    var body: some View {
        Text("Home").font(.title)
    }
}

struct DataV: View {
    var body: some View {
        Text("Data V").font(.title)
    }
}

struct GraphV: View {
    var body: some View {
        Text("Graph V").font(.title)
    }
}

Terms of Service

Privacy Policy

Cookie Policy