Code crew, I have a custom tab bar that works well until I add a navigation view to a pop-up option. Whenever I click the plus button, the tab bar moves up a quarter of the way.
Any thoughts on how I can remedy it?
I can post the code if someone is willing to take a look.
Hi Kyle,
Welcome to the Code Crew community.
Is this a SwiftUI project?
Hi Chris,
Yes indeed it is, apologies if I’ve posted this in the wrong section of the forum. If I am in the right place, I’ve posted my code below. I’m still learning SwiftUI so I appreciate any suggestions on making this better.
struct Homescreen : View {
@ObservedObject var viewRouter = ViewRouter()
@State var showPopUp = false
@State var isExploreTabSelected = false
@State var isProfileTabSelected = false
@State var isFriendsTabSelected = false
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
if self.viewRouter.currentView == "home" {
NewHome()
} else if self.viewRouter.currentView == "settings" {
LogOut()
}
else if self.viewRouter.currentView == "profile" {
NewProfile()
}
else if self.viewRouter.currentView == "explore" {
NewExplore()
}
else if self.viewRouter.currentView == "friends" {
NewFriend()
}
Spacer()
ZStack {
if self.showPopUp {
PlusMenu()
.offset(y: -geometry.size.height/6)
}
HStack {
Image(systemName: "house")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: geometry.size.width/5, height: 75)
.foregroundColor(self.viewRouter.currentView == "home" ? .black : .gray)
.onTapGesture {
self.viewRouter.currentView = "home"
self.isProfileTabSelected = false
self.isExploreTabSelected = false
self.isFriendsTabSelected = false
}
Image(isExploreTabSelected ? "explore_active": "explore" )
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: geometry.size.width/5, height: 75)
//.foregroundColor(self.viewRouter.currentView == "home" ? .black : .gray)
.onTapGesture {
self.viewRouter.currentView = "explore"
self.isExploreTabSelected = true
self.isProfileTabSelected = false
self.isFriendsTabSelected = false
}
ZStack {
Circle()
.foregroundColor(Color.white)
.frame(width: 75, height: 75)
Image(systemName: "plus.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 75, height: 75)
.foregroundColor(.black)
.rotationEffect(Angle(degrees: self.showPopUp ? 90 : 0))
}
.offset(y: -geometry.size.height/10/2)
.onTapGesture {
withAnimation {
self.showPopUp.toggle()
}
}
Image(isFriendsTabSelected ? "FRIENDSactive" : "FRIENDS")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: geometry.size.width/5, height: 75)
.onTapGesture {
self.viewRouter.currentView = "friends"
self.isProfileTabSelected = false
self.isExploreTabSelected = false
self.isFriendsTabSelected = true
}
Image(isProfileTabSelected ? "profile_active" : "profile")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: geometry.size.width/5, height: 75)
//.foregroundColor(self.viewRouter.currentView == "profile" ? .black : .gray)
.onTapGesture {
self.viewRouter.currentView = "profile"
self.isProfileTabSelected = true
self.isExploreTabSelected = false
self.isFriendsTabSelected = false
}
}
.frame(width: geometry.size.width, height: geometry.size.height/10)
.background(Color.white.shadow(radius: 2))
}
}.edgesIgnoringSafeArea(.all)
}
}
struct PlusMenu: View {
//@ObservedObject var viewRouter = ViewRouter()
@State var image = UIImage()
@State var isShowPhotoLibrary = false
@State var galleryPostisPresented = false
@State var journalPostisPresented = false
var body: some View {
NavigationView {
HStack(spacing: 50) {
Button(action: {
self.galleryPostisPresented.toggle() }, label: {
ZStack {
Circle()
.foregroundColor(Color("Color"))
.frame(width: 70, height: 70)
Image(systemName: "camera")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
}).sheet(isPresented: self.$galleryPostisPresented, content: {
NewGalleryPostView()
})
Button(action: {
self.journalPostisPresented.toggle()
}, label: {
ZStack {
Circle()
.foregroundColor(Color("Color"))
.frame(width: 70, height: 70)
Image(systemName: "photo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
}).sheet(isPresented: self.$journalPostisPresented, content: {
NewJournalPostView()
})
ZStack {
Circle()
.foregroundColor(Color("Color"))
.frame(width: 70, height: 70)
Image(systemName: "applelogo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
}.navigationBarTitle("")
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
.transition(.scale)
}.edgesIgnoringSafeArea(.all)
.padding(0)
.navigationBarTitle("")
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
}
I posted this on StackOverflow as well and as a noob I was informed this had too many absent dependencies. Here is the minimal version of the code that produces the same issue.
I did crib this code from https://blckbirds.com/post/custom-tab-bar-in-swiftui/ & https://github.com/BLCKBIRDS/CustomTabBarInSwiftUI and simply wrap the PlusMenu HStack in a navigationview causing the issue.
View {
@ObservedObject var viewRouter = ViewRouter()
@State var showPopUp = false
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
if self.viewRouter.currentView == "home" {
Text("Home")
} else if self.viewRouter.currentView == "settings" {
Text("Settings")
}
Spacer()
ZStack {
if self.showPopUp {
PlusMenu()
.offset(y: -geometry.size.height/6)
}
HStack {
Image(systemName: "house")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: geometry.size.width/3, height: 75)
.foregroundColor(self.viewRouter.currentView == "home" ? .black : .gray)
.onTapGesture {
self.viewRouter.currentView = "home"
}
ZStack {
Circle()
.foregroundColor(Color.white)
.frame(width: 75, height: 75)
Image(systemName: "plus.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 75, height: 75)
.foregroundColor(.blue)
.rotationEffect(Angle(degrees: self.showPopUp ? 90 : 0))
}
.offset(y: -geometry.size.height/10/2)
.onTapGesture {
withAnimation {
self.showPopUp.toggle()
}
}
Image(systemName: "gear")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: geometry.size.width/3, height: 75)
.foregroundColor(self.viewRouter.currentView == "settings" ? .black : .gray)
.onTapGesture {
self.viewRouter.currentView = "settings"
}
}
.frame(width: geometry.size.width, height: geometry.size.height/10)
.background(Color.white.shadow(radius: 2))
}
}.edgesIgnoringSafeArea(.bottom)
}
}
View {
NavigationView {
HStack(spacing: 50) {
ZStack {
Circle()
.foregroundColor(Color.blue)
.frame(width: 70, height: 70)
Image(systemName: "camera")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
ZStack {
Circle()
.foregroundColor(Color.blue)
.frame(width: 70, height: 70)
Image(systemName: "photo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
}
.transition(.scale)
}
}
Correct me if I am wrong but it looks like you are creating the Tab view without using a Tab Bar View that SwiftUI offers.
For example consider the following code (unrelated example insofar as I have used different icons because the base code is from another project that is a SwiftUI Tab Bar project but I added your button down the bottom similar to what you have):
struct ContentView: View {
@State private var showPopUp = false
var body: some View {
ZStack {
TabView {
EveryoneView()
.tabItem {
Image(systemName: "person.3")
Text("Everyone")
}
ContactedView()
.tabItem {
Image(systemName: "checkmark.circle")
Text("Contacted")
}
Text("")
.tabItem {
// Does nothing other than provide a space in the tab bar
}
UncontactedView()
.tabItem {
Image(systemName: "questionmark.diamond")
Text("Uncontacted")
}
MeView()
.tabItem {
Image(systemName: "person.crop.square")
Text("Me")
}
}
VStack {
Spacer()
ZStack {
Circle()
.foregroundColor(Color.white)
.frame(width: 75, height: 75)
Image(systemName: "plus.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 75, height: 75)
.foregroundColor(.black)
.rotationEffect(Angle(degrees: self.showPopUp ? 90 : 0))
}
.onTapGesture {
withAnimation {
self.showPopUp.toggle()
}
}
}
if showPopUp {
PlusMenuView()
}
}
}
}
struct EveryoneView: View {
var body: some View {
Text("Everyone")
.font(.largeTitle)
}
}
struct ContactedView: View {
var body: some View {
Text("Contacted")
.font(.largeTitle)
}
}
struct UncontactedView: View {
var body: some View {
Text("Un-Contacted")
.font(.largeTitle)
}
}
struct MeView: View {
var body: some View {
Text("Me")
.font(.largeTitle)
}
}
struct PlusMenuView: View {
@State var image = UIImage()
@State var isShowPhotoLibrary = false
@State var galleryPostisPresented = false
@State var journalPostisPresented = false
var body: some View {
VStack {
Spacer()
HStack(spacing: 50) {
Button(action: {
self.galleryPostisPresented.toggle()
}, label: {
ZStack {
Circle()
.foregroundColor(Color.red)
.frame(width: 70, height: 70)
Image(systemName: "camera")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
})
Button(action: {
self.journalPostisPresented.toggle()
}, label: {
ZStack {
Circle()
.foregroundColor(Color.red)
.frame(width: 70, height: 70)
Image(systemName: "photo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
})
ZStack {
Circle()
.foregroundColor(Color.red)
.frame(width: 70, height: 70)
Image(systemName: "applelogo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
.frame(width: 70, height: 70)
.foregroundColor(.white)
}
}
.padding(.bottom, 100)
}
}
}
That results in a screen that looks like this (the first two tabs at least):
The PlusMenuView code is modified to remove the .sheet(isPresented… code as those Views I don’t have.
Not sure if that is something you can work with but I thought I would post it nevertheless.
This certainly helps tremendously Chris thank you! The only reason I wasn’t using the tab view is because the tutorial I was following wasn’t using it, so I am happy to modify my code with what you’ve provided as this is probably the best practice anyway - thank you so much for the guidance!
1 Like