So I'm trying to navigate from one view to another in SwiftUI and have stumbled upon a problem.
My views looks like this and trying to navigation from one DetailView to another DetailView but as soon I push the navigation link I'm forced back to the first DetailView.
Any ideas on how to achieve navigation to the same view in SwiftUI?
ListView.swift
struct ListView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView(data: data)) {
Text("Navigate")
}
}
}
}
}
DetailView.swift
struct DetailView: View {
var body: some View {
VStack {
NavigationLink(destination: DetailView(data: otherData)) {
Text("Navigate")
}
}
}
}
EDIT:
Remove the NavigationView in DetailView as pointed out below but still facing the same issue.
Remove NavigationView from DetailView, there should be only one in stack, so when you navigate all new links are opened in original NavigationView:
struct DetailView: View {
var body: some View {
VStack {
NavigationLink(destination: DetailView(data: otherData)) {
Text("Navigate")
}
}
}
}
Related
I am making a menu for my game using NavigationView and NavigationLink. I have three views as such:
struct MainMenuView: View {
var body: some View {
NavigationView {
// relevant stuff
NavigationLink(destination: CustomGameSettingsView()) {
Text("Custom Game")
}
}
}
}
struct CustomGameSettingsView: View {
var body: some View {
NavigationView {
// ui to change game settings and stuff
NavigationLink(destination: MyGameView(customSettings)) {
Text("Play Game!")
}
}
}
}
Note that the CustomGameSettingsView shows the navigationBarBackButton
struct MyGameView: View {
var body: some View {
myGameViews {
// stuff
}
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
.navigationBarTitle(Text("myGame"))
.edgesIgnoringSafeArea([.top, .bottom])
// these are the things I have tried to get rid of the navigationBackButton
}
.onAppear() {
self.navigationBarBackButtonHidden(true)
} // another thing I tried
}
When I navigate from MainMenuView to CustomGameSettingsView, I gain a navigationBarBackButton which stays with me when I navigate to MyGameView. How do I get rid of that on the final navigation? I want the back button on the settings menu but I want my game to be fullscreen. Is NavigationView the wrong tool in this instance?
Thank you in advance.
The problem here is you use another NavigationView{} inside the CustomGameSettingsView. You don't have to use another NavigationView because all your views (except MainMenuView) are already inside the NavigationView of the MainMenuView.
To fix this, replace the NavigationView inside the CustomGameSettingsView with a different container, then everything will work fine. Also, remove all your onAppear{}.
struct CustomGameSettingsView: View {
var body: some View {
VStack { //replace NavigationView with something else
NavigationLink(destination: MyGameView()) {
Text("Play Game!")
}
}
}
}
I'm new to SwiftUI and struggling to move MainView to LoginView by clicking Text() in ChildView.
I tried make NavigationView and NavigationLink like this code but it's not working. It's much more complex in real code but I show only simple structure of my code to explain.
struct ContentView: View {
#State private var currViewIdx: Int = 0
var body: some View {
NavigationView {
CurrentView(currViewIdx: $currViewIdx)
}
}
}
struct CurrentView: View {
#Binding var currViewIdx: Int
var body: some View {
if self.currViewIdx == 0 {
HomeView()
.onTapGesture {
self.currViewIdx = 0
}
} else {
//SomeView.onTapGesture(self.currViewIdx = 1)
}
}
}
struct HomeView: View {
var body: some View {
NavigationLink(destination: TestView()) {
Text("Go TestView")
.contentShape(Rectangle())
}
}
}
struct TestView: View {
var body: some View {
Text("Here is Test View")
}
}
I think, the top hierarchy view, ContentView, has NavigationView and it should be changed when I click Text("Go TestView") in HomeView because it's in NavagationLink.
But the ContentView is not changed to TestView although I touch Text("Go TestView"). How to solve this problem? I considered way to add one more State value to change top level view, but it seems not good if I'll make lots of more values
Thank you
I am developing an app with SwiftUI.
I have a NavigationView and I have buttons on the navigation bar. I want to replace the current view (which is a result of a TabView selection) with another one.
Basically, when the user clicks "Edit" button, I want to replace the view with another view to make the edition and when the user is done, the previous view is restored by clicking on a "Done" button.
I could just use a variable to dynamically choose which view is displayed on the current tab view, but I feel like this isn't the "right way to do" in SwiftUI. And this way I could not apply any transition visual effect.
Some code samples to explain what I am looking for.
private extension ContentView {
#ViewBuilder
var navigationBarLeadingItems: some View {
if tabSelection == 3 {
Button(action: {
print("Edit pressed")
// Here I want to replace the tabSelection 3 view by another view temporarly and update the navigation bar items
}) {
Text("Edit")
}
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
TabView(selection: $tabSelection) {
ContactPage()
.tabItem {
Text("1")
}
.tag(1)
Text("Chats")
.tabItem() {
Text("2")
}
.tag(2)
SettingsView()
.tabItem {
Text("3")
}
.tag(3)
}.navigationBarItems(leading: navigationBarLeadingItems)
}
}
}
Thank you
EDIT
I have a working version where I simply update a toggle variable in my button action that makes my view display one or another thing, it is working but I cannot apply any animation effect on it, and it doesn't look "right" in SwiftUI, I guess there is something better that I do not know.
If you just want to add animations you can try:
struct ContentView: View {
...
#State var showEditView = false
var body: some View {
NavigationView {
TabView(selection: $tabSelection) {
...
view3
.tabItem {
Text("3")
}
.tag(3)
}
.navigationBarItems(leading: navigationBarLeadingItems)
}
}
}
private extension ContentView {
var view3: some View {
VStack {
if showEditView {
FormView()
.background(Color.red)
.transition(.slide)
} else {
Text("View 3")
.background(Color.blue)
.transition(.slide)
}
}
}
}
struct FormView: View {
var body: some View {
Form {
Text("test")
}
}
}
A possible alternative is to use a ViewRouter: How To Navigate Between Views In SwiftUI By Using An #EnvironmentObject.
It seems as though I'm unable to choose which pages I want to hide the Navigation Bar on in swift UI.
I have the following screens:
Main
struct Main: View {
var body: some View {
NavigationView {
Home()
}
}
}
Home
struct Home: View {
var body: some View {
NavigationLink(destination: Details()) {
Text("Go Next")
}
// I expect the navigation bar to show up here, and it does
.navigationBarTitle("Home")
.navigationBarHidden(false)
}
}
Details
struct Details: View {
#Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body: some View {
Button(action: { self.mode.wrappedValue.dismiss() }) {
Text("Go Back")
}
// I expect the navigation bar to be hidden here
// At first, it is hidden. Then, after a second, it pops up
// with the title "Details"
.navigationBarTitle("Details")
.navigationBarHidden(true)
}
}
Either I'm doing this wrong (likely), or Apple has some work to do (also likely).
As I saw earlier, something comes wrong, when you use both:
.navigationBarTitle("some text")
.navigationBarHidden(true)
in code below there is no navigation bar staff and nothing pops up:
struct Details: View {
#Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body: some View {
Button(action: { self.mode.wrappedValue.dismiss() }) {
Text("Go Back")
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true) // even no back button
}
}
I'm getting a strange crash from pretty normal navigation on my SwiftUI app
I have a simple tab view :
struct FFTabView: View {
var body: some View {
TabView {
LibraryView2()
}
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
.navigationBarTitle("", displayMode: .inline)
}
}
// MARK: -
struct LibraryView2: View {
var body: some View {
VStack {
NavigationLink(destination: Foo()) {
Text("go to foo")
}
}
.tabItem {
Image(systemName: "square.grid.2x2.fill")
Text("Skill Library")
}
}
}
struct Foo: View {
var body: some View {
Text("foo view")
}
}
When I go back via my nav bar, from Foo I get a crash: Tried to pop to a view controller that doesn't exist
Any idea what's going on here? I can't find anything related to this and SwiftUI so figured I'd post. Thanks
Although you didn't specify, I assume your FFTabView is wrapped in a NavigationView somewhere.
Ultimately, then, your view hierarchy looks like
NavigationView {
TabView {
NavigationLink {
...
}
}
}
If you restructure your view hierarchy so it's like
TabView {
NavigationView {
NavigationLink {
...
}
}
}
The crash doesn't happen.
Edit:
I have confirmed that it is related to the regression/bug discussed in this answer, introduced in Xcode 11.2. Your original code works fine in Xcode 11.1.