In the previous posts, we have seen the fundaments of the SwiftUI. Now is the moment to starts to build something a bit more complex, how to implement the navigation in our apps with NavigationBar and the TabView.
NavigationBar
Start from the code of the previous post (https://nicoladefilippo.com/list-in-swiftui/):
struct Vehicle: Identifiable { var id = UUID() var name: String var image: String } struct ContentView: View { @State var vehicles = [Vehicle(name: "car", image: "car"), Vehicle(name: "bus", image: "bus"), Vehicle(name: "tram", image: "tram"), Vehicle(name: "bicycle", image: "bicycle")] var body: some View { List { ForEach(vehicles) { vehicle in RowView(vehicle: vehicle) } .onDelete { (indexSet) in self.vehicles.remove(atOffsets: indexSet) } } } } struct RowView: View { var vehicle: Vehicle var body: some View { HStack { Image(systemName: vehicle.image) .resizable() .frame(width: 60, height: 60) Text(vehicle.name) } } }
We want to tap on one row and skip to a new view.
The first step is add a NavigationView:
var body: some View { NavigationView { List { ForEach(vehicles) { vehicle in NavigationLink(destination: EmptyView()) { RowView(vehicle: vehicle) } } .onDelete { (indexSet) in self.vehicles.remove(atOffsets: indexSet) } }.navigationTitle("Transports") } }
In the NavigationView we insert the List how in the previous example. To add a title to the NavigationView, you have to use the navigationTitle function.
To jump to another view we have to use the NavigationLink. In the body of this, we insert the RowView (we want to click on the row to jump) and how destination we use EmptyView, a blank default view, so if we tap on any row:
We want a not empty view but a view that display something.
Let’s go to create a view. First, from the file menu select the new file voice and then:
From the dialog select SwiftUI View and call it VehicleView.
Replace the EmptyView with the VehicleView:
NavigationLink(destination: VehicleView()) { RowView(vehicle: vehicle) }
Now tapping on the list you jump on the new view and you’ll see “hello world”.
To show the info of the selected row, change the code of the VehicleView in:
import SwiftUI struct VehicleView: View { var vehicle: Vehicle var body: some View { VStack(spacing: 20) { Image(systemName: vehicle.image) .resizable() .frame(width: 300, height: 300) Text("Selected the \(vehicle.name.uppercased())") .font(.title) Spacer() } } } struct VehicleView_Previews: PreviewProvider { static var previews: some View { VehicleView(vehicle: Vehicle(name: "car", image: "car")) } }
In the view, there is defined a var of Vehicle type that we suppose contains the row passed, and show the information how defined in the VStack (see the post about VStack https://nicoladefilippo.com/layout-in-swiftui/). Note that in the VehicleView_Previews we pass a vehicle, it’s a default view used only for the preview (it’s helpful when you “design” the view without running the code).
To complete the navigation, we must change also the ContentView:
NavigationLink(destination: VehicleView(vehicle: vehicle)) { RowView(vehicle: vehicle) }
How you can see we pass to the VehicleView vehicle. If everything it’s ok, if you tap the bus, you should have:
Is possible to have the title of the bar in the centre? Sure, replace the navigationTitle with the navigationBarTitle in this way:
var body: some View { NavigationView { List { ForEach(vehicles) { vehicle in NavigationLink(destination: VehicleView(vehicle: vehicle)) { RowView(vehicle: vehicle) } } .onDelete { (indexSet) in self.vehicles.remove(atOffsets: indexSet) } }.navigationBarTitle("Transports", displayMode: .inline) } }
Note the displayMode set to .inline.
Tab View
Now see how to define the TabView:
struct ContentView: View { var body: some View { TabView { Text("Tab1") // View First Tab .tabItem { Label("Vehicles", systemImage: "list.dash")} Text("Tab2") // View Second Tab .tabItem { Label("Profile", systemImage: "person.circle")} } } }
The magic word is TabView. In the body of this, we insert the views with relative tabItem. The view is what we see in the tab, the tabItem is what we see in the tab bar.
Now to create something more complex, we can use the code from the navigationview example.
First, create a VehiclesView (note the plural).
import SwiftUI struct Vehicle: Identifiable { var id = UUID() var name: String var image: String } struct VehiclesView: View { @State var vehicles = [Vehicle(name: "car", image: "car"), Vehicle(name: "bus", image: "bus"), Vehicle(name: "tram", image: "tram"), Vehicle(name: "bicycle", image: "bicycle")] var body: some View { NavigationView { List { ForEach(vehicles) { vehicle in NavigationLink(destination: VehicleView(vehicle: vehicle)) { RowView(vehicle: vehicle) } } .onDelete { (indexSet) in self.vehicles.remove(atOffsets: indexSet) } }.navigationBarTitle("Transports", displayMode: .inline) } } } struct RowView: View { var vehicle: Vehicle var body: some View { HStack { Image(systemName: vehicle.image) .resizable() .frame(width: 60, height: 60) Text(vehicle.name) } } } struct VehiclesView_Previews: PreviewProvider { static var previews: some View { VehiclesView() } }
Then, create a VehicleView as in the NavigationView example and then change the TabView:
struct ContentView: View { var body: some View { TabView { VehiclesView() // View First Tab .tabItem { Label("Vehicles", systemImage: "list.dash")} Text("Tab2") // View Second Tab .tabItem { Label("Profile", systemImage: "person.circle")} } } }
Now in the first tab, we have a navigation view and we can navigate in the first tab.
For exercise, you can create a profile page.
Note: English is not my native language, so I’m sorry for some errors. I appreciate it if your correct me.
2 comments