Reputation: 152
I want to create a design similar to the image above. To create the bottom TabView, I used this code:
import SwiftUI
struct ParentTabView: View {
var body: some View {
TabView {
HomeView()
.tabItem {
Image(systemName: "star.fill")
Text("Home")
}
Text("Second Tab")
.tabItem {
Image(systemName: "star.fill")
Text("Discover")
}
Text("Third Tab")
.tabItem {
Image(systemName: "star.fill")
Text("Settings")
}
}
}
}
and the HomeView
struct HomeView: View {
var body: some View {
NavigationView {
Text("Home")
.navigationBarItems(
trailing:
Button(action: {
}) {
Image(systemName: "plus")
}
)
.navigationTitle("Home")
}
}
}
The problem I encounter is with the top navigation bar, as I'm not able to edit the NavigationView to receive other views below the title. I can set the title and add the "plus" button, but not edit the whole top bar.
Can NavigationView be customized in such a way and if not, how can I achieve that result while still keeping the advantages NavigationViews offer, such as NavigationLinks etc.
Upvotes: 1
Views: 195
Reputation: 207
The NavigationBar provided by Apple is not quite customizable. You might want to create your customized navigation bar for this use case.
Fortunately, I had some time in hand so I created a simple reusable navigation bar that looks like the outcome you wanted, please take a look below.
You have to to hide Apple's navigation bar, and add the custom navigation bar as an overlay to your navigation view (as seen in the image below):
This is the code for the reusable custom navigation view:
enum CustomNavigationBarItem: String, CaseIterable {
case dashboard = "Dashboard"
case feed = "Feed"
case followers = "Followers"
}
struct CustomNavigationBar: View {
var title: String
var items: [CustomNavigationBarItem]
@Binding var selectedItem: CustomNavigationBarItem
var buttonAction: () -> ()
var body: some View {
VStack {
VStack(spacing: 10) {
CustomNavigationBarHeader(title: title, buttonAction: buttonAction)
HStack(spacing: 0) {
ForEach(items, id: \.self) { item in
CustomNavigationBarItemView(text: item.rawValue, isSelected: selectedItem == item)
.onTapGesture {
selectedItem = item
}
}
}
}
.background(Color(#colorLiteral(red: 0.1036974415, green: 0.1036974415, blue: 0.1036974415, alpha: 1)).edgesIgnoringSafeArea(.all))
Spacer()
}
}
}
struct CustomNavigationBarItemView: View {
var text: String
var isSelected: Bool
var body: some View {
Text(text)
.foregroundColor(isSelected ? .blue : Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)))
.frame(maxWidth: .infinity)
.padding(.vertical, 10)
.padding(.horizontal, 6)
.overlay(
VStack {
Spacer()
Color.blue
.frame(height: 2)
.opacity(isSelected ? 1 : 0)
.animation(.default)
}
)
}
}
struct CustomNavigationBarHeader: View {
var title: String
var buttonAction: () -> ()
var body: some View {
HStack {
Text(title)
.font(.title)
.bold()
Spacer()
Button(action: buttonAction, label: {
Image(systemName: "plus")
})
.font(.headline)
}
.padding(.horizontal)
}
}
HomeView Code:
struct HomeView: View {
@State private var selectedNavigationBarItem: CustomNavigationBarItem = .dashboard
@State private var numPlusButtonClicked: Int = 0
var body: some View {
NavigationView {
VStack {
Text("Home")
switch selectedNavigationBarItem {
case .dashboard:
Text("Currently Showing: Dashboard") //Use your view here
case .feed:
Text("Currently Showing: Feed") //Use your view here
case .followers:
Text("Currently Showing: Followers") //Use your views here
}
Text("Plus Button Clicked \(numPlusButtonClicked) times.")
}
}
.navigationBarHidden(true)
.overlay(
CustomNavigationBar(title: "Home",
items: [.dashboard, .feed, .followers],
selectedItem: $selectedNavigationBarItem) {
numPlusButtonClicked += 1 // Code executed when the "+" button gets called
}
)
}
}
Notes:
Best of luck!
Edit: Added code for HomeView
Upvotes: 2