SwiftUI double navigation bar
Remove the NavigationView
from SecondView
.
The NavigationLink
puts the second view inside the first views navigations view, so you do not need to put it inside a second one.
You can still update the title of the view from SecondView
like so:
struct SecondView: View {
var body: some View {
Text("My View")
.navigationBarTitle("Second View")
}
}
SwiftUI - Two navigation bars
You are adding second NavigationView in RegisterView. That is the issue! because of using ContentView, for solving use MainView().
struct RegisterView: View {
@ObservedObject var registerController = RegisterController()
@State private var showingRegistrationAlert = false
@State var navigateNext = false
let lightGreyColor = Color(red: 239.0/255.0, green: 243.0/255.0, blue: 244.0/255.0, opacity: 1.0)
var body: some View {
VStack {
VStack(alignment: .leading) {
Spacer()
NavigationLink(destination: MainView(), isActive:$navigateNext) { // <<: here
Text("")
}
Button(action: { if registerController.validateRegistration() {
showingRegistrationAlert.toggle()
}}) {
Text("Enviar registro")
}
.alert(isPresented: $showingRegistrationAlert) {
Alert(title: Text("Se registro correctamente"), dismissButton: .default(Text("Ok"), action: {
navigateNext.toggle()
}))
}
.padding()
.navigationBarTitle(Text("Registracion"), displayMode: .inline)
}
}
Double Navigation Bar SwiftUI
You don't need second NavigationView, there should be only one in navigation stack, ie
struct SecondView: View {
var body: some View {
// NavigationView { // << remove this one !!
VStack {
Text("This is Second View")
NavigationLink(destination: ThirdView()) {
Text("Show Third View")
}
}
.navigationBarTitle("Second View", displayMode: .inline)
// }
}
}
How can I avoid nested Navigation Bars in SwiftUI?
You should only have one NavigationView
in your view hierarchy, as an ancestor of the menu view. You can then use NavigationLink
s at any level of the hierarchy under that.
So, for example, your root view could be defined like this:
struct RootView: View {
var body: some View {
NavigationView {
MenuView()
.navigationBarItems(trailing: profileButton)
}
}
private var profileButton: some View {
Button(action: { }) {
Image(systemName: "person.crop.circle")
}
}
}
Then your menu view has NavigationLink
s to the appropriate views:
struct MenuView: View {
var body: some View {
List {
link(icon: "calendar", label: "Appointments", destination: AppointmentListView())
link(icon: "list.bullet", label: "Work Order List", destination: WorkOrderListView())
link(icon: "rectangle.stack.person.crop", label: "Contacts", destination: ContactListView())
link(icon: "calendar", label: "My Calendar", destination: MyCalendarView())
}.navigationBarTitle(Text("Menu"), displayMode: .large)
}
private func link<Destination: View>(icon: String, label: String, destination: Destination) -> some View {
return NavigationLink(destination: destination) {
HStack {
Image(systemName: icon)
Text(label)
}
}
}
}
Your appointment list view also contains NavigationLink
s to the appointment detail views:
struct AppointmentListView: View {
var body: some View {
List {
link(destination: AppointmentDetailView())
link(destination: AppointmentDetailView())
link(destination: AppointmentDetailView())
}.navigationBarTitle("Appointments")
}
private func link<Destination: View>(destination: Destination) -> some View {
NavigationLink(destination: destination) {
AppointmentView()
}
}
}
Result:
How to create a shared navigation bar to inter-navigate among multiple views in SwiftUI?
You would use a TabView {...}
to accomplish this. Effectively you instantiate your views inside of the TabView
then add an item modifier to each view.
var body: some View {
TabView {
Text("A")
.tabItem { Text("A") }
Text("B")
.tabItem { Text("B") }
Text("C")
.tabItem { Text("C") }
}
init() {
UITabBar.appearance().backgroundColor = UIColor.red
}
}
What this code does: https://i.stack.imgur.com/CKBHm.gif
For added clarity, you can add any item you want to a TabView. It basically acts as a container for the views that you add.
struct ContentView: View {
var body: some View {
TabView {
FirstView()
.tabItem { Text("A") }
SecondView()
.tabItem { Text("B") }
ThirdView()
.tabItem { Text("C") }
}
}
}
struct FirstView: View {
var body: some View {
Text("A")
}
}
struct SecondView: View {
var body: some View {
Text("B")
}
}
struct ThirdView: View {
var body: some View {
Text("C")
}
}
Custom Tab Bar
This is a very simple case where we simply swap out the parent VStack{}
based on the enum that we created. When it's first initialized this would set the .first
page and that would be the one displayed. Anytime we change it with a button action located in the HStack{}
the view is updated. This is especially useful if you want to add something more to the tab bar beyond text or an image. You could also add the selectedPage
to an @EnvironmentObject
to have control of those pages from anywhere in the app. It's especially useful when creating logins or landing pages, where you need to swap the navigation stack.
struct ContentView: View {
@State var selectedPage: SelectedPage = .first
var body: some View {
VStack {
VStack {
switch selectedPage {
case .first:
FirstView()
case .second:
SecondView()
case .third:
ThirdView()
}
}
Spacer()
HStack {
Button(action: { selectedPage = .first }, label: {
Text("A")
})
Spacer()
Button(action: { selectedPage = .second }, label: {
Text("B")
})
Spacer()
Button(action: { selectedPage = .third }, label: {
Text("C")
})
}.padding(.horizontal, 30)
}
}
}
enum SelectedPage {
case first, second, third
}
Hiding Navigation Bar in case of multiple Navigation Views in SwiftUI
If you want to hide navigation bar completely at third view here is possible approach. (Note: btw in one view hierarchy there must be only one NavigationView, so another one in ThirdView is not needed)
Tested with Xcode 11.4 / iOS 13.4
class HideBarViewModel: ObservableObject {
@Published var isHidden = false
}
struct FirstView: View {
@ObservedObject var vm = HideBarViewModel()
init() {
UINavigationBar.appearance().backgroundColor = UIColor.green
}
var body: some View {
NavigationView {
NavigationLink(destination: SecondView()) {
Text("Second View")
}.navigationBarTitle("First View")
.navigationBarHidden(vm.isHidden)
}.environmentObject(vm)
}
}
// Second View
struct SecondView: View {
var body: some View {
NavigationLink(destination: ThirdView()) {
Text("Third View")
}
}
}
// Third View
struct ThirdView: View {
@EnvironmentObject var vm: HideBarViewModel
var body: some View {
Text("Welcome")
.onAppear {
self.vm.isHidden = true
}
}
}
SwiftUI Navigation Bar Item with different destinations
You could add a function (in your view) that routes to the right destination (depending on the value of the "selection" property).
@ViewBuilder func addView() -> some View {
switch selection {
case .income: Text("Income destination")
case .expenses: Text("Expenses destination")
default: Rectangle()
}
}
Your NavigationLink
calls this view builder :
NavigationLink("Add", destination: addView())
Related Topics
Calculating Angle Between Two Points on Edge of Circle Swift Spritekit
iOS 9 iPad Keyboard Get Rid of "Undo View"
What Does the Swift 'Mutating' Keyword Mean
How to Pass Protocol with Associated Type (Generic Protocol) as Parameter in Swift
Convincing Swift That a Function Will Never Return, Due to a Thrown Exception
Swift Optional Escaping Closure
Add Links to Swift Classes in the Quick Help Documentation Comments
Swift Uifont Ibinspectable - Is It Possible
In Swiftui How to Set the Environment Variable of Editmode in an Xcodepreview
How to Disable the Show Tab Bar Menu Option in Swiftui
How to Get the Edited Image from Uiimagepickercontroller in Swift
Trying to Use Keychainitemwrapper by Apple "Translated" to Swift
Vapor 3 Beta Example Endpoint Request