Reputation: 1837
Having an issue in SwiftUI where some Views are growing bigger vertically than the size of the device when using .edgesIgnoringSafeArea(.bottom). On an iPhone 11 Pro which is 812 pixels high I am seeing a view of size 846. I am using the Debug View Hierarchy to verify it. This has been tested on Xcode 11.4.1 and 11.1 and exists in both versions and probably all in between.
I have included sample code below.
I am pretty sure this is a SwiftUI bug, but was wondering if anyone has a workaround for it. I need the edgesIgnoringSafeArea(.bottom) code to draw the TabBar, and for the ProfileView() to extend to the bottom of the screen when I hide my custom tab bar.
struct ContentView: View {
var body: some View {
MainTabView()
}
}
struct MainTabView : View {
enum Item : CaseIterable {
case home
case resources
case profile
}
@State private var selected : Item = .home
var body: some View {
VStack(spacing: 0.0) {
ZStack {
HomeView()
.zIndex(selected == .home ? 1 : 0)
ResourcesView()
.zIndex(selected == .resources ? 1 : 0)
ProfileView()
.zIndex(selected == .profile ? 1 : 0)
}
// Code here for building and showing/hiding a Toolbar
// Basically just a HStack with a few buttons in it
}
.edgesIgnoringSafeArea(.bottom) // <- This causes the screen to jump to 846
}
}
struct ProfileView : View {
@State private var showQuestionnaireView = false
var body: some View {
NavigationView {
ZStack {
NavigationLink(destination: QuestionnaireView( showQuestionnaireView:$showQuestionnaireView),
isActive: $showQuestionnaireView) {
Text("Show Questionnaire View")
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
}
struct QuestionnaireView : View {
@Binding var showQuestionnaireView : Bool
var body: some View {
GeometryReader { screenGeometry in
ZStack {
Color.orange
VStack {
Text("Top")
Spacer()
Text("Bottom")
}
}
}
}
}
HomeView() and ResourcesView() are just copies of ProfileView() that do their own thing.
When you run it you will see a button, push the button and a hidden Navigation Stack View pushes on the QuestionnaireView, this view contains a VStack with two text fields, neither of which you will be able to see due to this issue. Understandably the top one is behind the notch, but the bottom one is off the bottom of the screen. In my real project this issue is rarely seen at runtime, but switching between dark mode and light mode shows it. In the above code there is no need to switch appearances.
EDIT: FB7677794 for anyone interested, have not received any updates from Apple since lodging it 3 weeks ago.
EDIT2: Added some more code to MainTabBar
Update: This is fixed in Xcode 12 Beta 2
Upvotes: 2
Views: 3500
Reputation: 335
After reading the updated question I have made some changes and tried to make a small demo. In this, I am using the same approach as before, put NavigationView
in your main tab view and with this you don't have to hide and show every time you come or leave your main tab view.
import SwiftUI
struct ContentView: View {
var body: some View {
MainTabView()
}
}
struct MainTabView : View {
enum Item : CaseIterable {
case home
case resources
case profile
}
@State private var selected : Item = .home
var body: some View {
NavigationView {
VStack(spacing: 0.0) {
ZStack {
Group {
HomeView()
.zIndex(selected == .home ? 1 : 0)
ResourcesView()
.zIndex(selected == .resources ? 1 : 0)
ProfileView()
.zIndex(selected == .profile ? 1 : 0)
}
.frame(minWidth: .zero, maxWidth: .infinity, minHeight: .zero, maxHeight: .infinity)
.background(Color.white)
}
HStack {
Group {
Image(systemName: "house.fill")
.onTapGesture {
self.selected = .home
}
Spacer()
Image(systemName: "plus.app.fill")
.onTapGesture {
self.selected = .resources
}
Spacer()
Image(systemName: "questionmark.square.fill")
.onTapGesture {
self.selected = .profile
}
}
.padding(.horizontal, 30)
}
.frame(height: 40)
.foregroundColor(Color.white)
.background(Color.gray)
// Code here for building and showing/hiding a Toolbar
// Basically just a HStack with a few buttons in it
}
.edgesIgnoringSafeArea(.bottom)
} // <- This causes the screen to jump to 846
}
}
struct ProfileView : View {
@State private var showQuestionnaireView = false
var body: some View {
// NavigationView {
ZStack {
NavigationLink(destination: QuestionnaireView( showQuestionnaireView:$showQuestionnaireView),
isActive: $showQuestionnaireView) {
Text("Show Questionnaire View")
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
// }
}
}
struct QuestionnaireView : View {
@Binding var showQuestionnaireView : Bool
var body: some View {
GeometryReader { screenGeometry in
ZStack {
Color.orange
VStack {
Text("Top")
Spacer()
Text("Bottom")
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
}
struct HomeView: View {
var body: some View {
NavigationLink(destination: SecondView()) {
Text("Home View")
}
}
}
struct ResourcesView: View {
var body: some View {
NavigationLink(destination: SecondView()) {
Text("Resources View")
}
}
}
struct SecondView: View {
var body: some View {
Text("Second view in navigation")
.background(Color.black)
.foregroundColor(.white)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice(PreviewDevice(rawValue: "iPhone 11"))
}
}
Upvotes: 2
Reputation: 258117
It is due to undefined size for NavigationView
. When you add your custom tab bar component, as in example below, that limits bottom area, the NavigationView will layout correctly.
Tested with Xcode 11.4 / iOS 13.4
struct MainTabView : View {
var body: some View {
VStack(spacing: 0.0) {
ZStack {
Color(.cyan)
ProfileView() // << this injects NavigationView
}
HStack { // custom tab bar
Button(action: {}) { Image(systemName: "1.circle").padding() }
Button(action: {}) { Image(systemName: "2.circle").padding() }
Button(action: {}) { Image(systemName: "3.circle").padding() }
}.padding(.bottom)
}
.edgesIgnoringSafeArea(.bottom) // works !!
}
}
Upvotes: 2