Hide NavigationView bar in landscape mode and delay in hiding in SwiftUI - ios

I'm still learning to SwiftUI and am playing with the NavigationView and I am able to hide the top navigation bar in portrait mode but have two issues.
1.) In landscape mode, there's a top bar that still sits on top of the view. Pulling it down brings down the notification center/settings
2.) After tapping the button in the view, it moves to the DetailView, but the top navigation bar is loaded briefly and then hides. How to stop the navigation from loading.
GIF of button to next view - the flow from tapping button to moving to next view to changing to landscape mode
Any feedback or approach is appreciated. Thanks!
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView()) {
Text("Hello World")
.fontWeight(.bold)
.font(.title)
.padding()
.background(Color.blue)
.cornerRadius(40)
.foregroundColor(.blue)
.padding(10)
.overlay(
RoundedRectangle(cornerRadius: 40)
)
}
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
//.edgesIgnoringSafeArea([.top, .bottom])
//.navigationViewStyle(StackNavigationViewStyle())
//.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
}
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
//.statusBar(hidden: true)
}
}

I was also seeing the navigation bar shown briefly in the destination view before it disappeared. To fix that, I added the navigation bar properties to the destination view argument inside the NavigationLink call. For your example, it would look like this:
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView()
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
) { // The rest of your code...

Related

SwiftUI - How to programatically scroll to top and show a large navigation title?

Recently added to iOS 14 ScrollViewReader added a way to programmatically scroll to a view in SwiftUI.
Q: Is there a way to scroll past the topmost element in ScrollView and reveal a large navigation title?
Expected effect:
Large navigation title after scrolling to top
Outcome:
Inline navigation title after scrolling to top
Code snippet for reference:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
ScrollViewReader { proxy in
ScrollView {
Rectangle()
.fill(.yellow)
.aspectRatio(contentMode: .fit)
.id("scrollID")
Rectangle()
.fill(.blue)
.aspectRatio(contentMode: .fit)
Rectangle()
.fill(.green)
.aspectRatio(contentMode: .fit)
Rectangle()
.fill(.red)
.aspectRatio(contentMode: .fit)
Button("Scroll to top") {
withAnimation {
proxy.scrollTo("scrollID")
}
}
}
.navigationTitle("Navigation")
}
}
}
}
This code scrolls to a top rectangle on the button tap but it doesn't reveal the default large navigation title. How could I achieve that?
(I haven't tested it!) Try:
declare state var to toggle navigation display mode
add .navigationBarTitle("Home", displayMode: showLargeDisplayMode ? .large : .inline)
toggle showLargeDisplayMode after proxy.scrollTo("scrollID")

SwiftUI - Views inside TabView jump after a second if TabView is nested in NavigationLink

My setup
Entry point (ContentView):
struct ContentView: View {
var body: some View {
NavigationView {
FirstView()
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
}
}
}
FirstView:
struct FirstView : View {
var body : some View {
NavigationLink(destination:
SecondView()
.navigationBarTitle("")
.navigationBarHidden(true)) {
Text("Fourth View")
}
}
}
SecondView:
struct SecondView : View {
var body : some View {
TabView {
FirstTabView()
.tabItem {
Image(systemName: "play.circle.fill")
Text("First Tab")
}
.navigationBarTitle("First Tab")
.navigationBarHidden(true)
SecondTabView()
.tabItem {
Image(systemName: "bell.fill")
Text("Second Tab")
}
.navigationBarTitle("Second Tab")
.navigationBarHidden(true)
}
}
}
FirstTabView
struct FirstTabView : View {
var body : some View {
VStack {
HStack(spacing: 10) {
Spacer()
Text("FIRST")
Spacer()
Text("SECOND")
Spacer()
}
.padding(.all)
Spacer()
}
.border(Color.red, width: 5)
}
}
And SecondTabView is very similar to the first one so I won't include it.
The issue
The issue I am having right now is that the content of my TabViews jump up ignoring safe areas (For clarification see the attached screenshots). The view actually displays perfectly fine and as expected for a brief moment and then immediately jumps up breaking everything.
I have found that this is only happening if the TabView is loaded via NavigationLink as I do right now. If I directly load the SecondView() inside my NavigationView on ContentView (or in other words its the first view that I load) then the issue is gone and everything works as expected.
I am sorry that I wasn't able to include GIF of the problem - the View starts off as the expected result and then after a seconds jumps up and becomes what you see on the actual result.
Expected Result
Actual Result
NOTE: On iPhones with notch my text is not even visible. Also I've put thick border in order to make my point more clear.
EDIT
I just found out that locking the device and then unlocking it brings the screen back to normal.

How to hide NavigationBar in SwiftUI for all types of devices?

I have a view hierarchy like this: SplashView -> MainView.
SplashView doesn't need to have NavigationBar, so I disable it:
NavigationView {
VStack { /* some stuff */}
}
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
.edgesIgnoringSafeArea([.top, .bottom])
In MainView I need an inline Navigation Bar
NavigationView {
ZStack{ /* some stuff */ }
}.navigationBarTitle("TEST TITLE", displayMode: .inline)
.navigationBarHidden(false)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: EmptyView())
.navigationBarItems(trailing: HStack {
Button("Test1") { print("test1")
}
Button("Test2") {
print("test2")
}
})
}
As result, I have this on iPhone 11:
And on iPhone SE 2nd gen. (simillar on iPhone 8 etc.):
And if you manage, you can click "Back button" and go to the SplashView!
Why it works like this and what I should do to fix it?
I think, the problem is you have the NavigationView as a root view for both screens. In this case you push the NavigationView in another NavigationView. So, you need the only one NavigationView in your project. So, change the body property of your MainView by removing the NavigationView
ZStack{ /* some stuff */ }
}.navigationBarTitle("TEST TITLE", displayMode: .inline)
.navigationBarHidden(false)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: EmptyView())
.navigationBarItems(trailing: HStack {
Button("Test1") { print("test1")
}
Button("Test2") {
print("test2")
}
})

How to permanently hide NavigationView nav bar in SwiftUI

I believe the recommended way to hide the navigation bar in SwiftUI is as follows (placed on the child of the NavigationView) however when a button is tapped on the view, the view updates itself & the nav bar reappears even though I'm using a constant value of true to hide the bar
.navigationBarTitle("")
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
How do I get the NavigationView's bar to stay hidden on this view?
EDIT
Here is the code for NavigationView, when a gesture/tap happens in a nested subview inside props.selectedView the bar appears again
NavigationView {
GeometryReader { geometry in
VStack(spacing: 0) {
ZStack {
VStack {
props.selectedView
Spacer()
.frame(height: searchHeaderHeight)
}
Search()
}
TabBar()
.frame(width: geometry.size.width, height: 60)
.padding(.bottom, geometry.safeAreaInsets.bottom)
.background(Color(.systemGroupedBackground))
}
.frame(width: geometry.size.width)
.edgesIgnoringSafeArea(.bottom)
}
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
}.navigationViewStyle(StackNavigationViewStyle())

Placing interactable views in front of a NavigationView's hidden navigation bar

I have a NavigationView with a NavigationButton inside of it, but I cannot get the NavigationButton to be at the top of the screen and still be able to be pressed, even though the navigation bar is hidden.
This code:
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
NavigationButton(destination: Text("Button Clicked")) {
Text("Hello World")
.background(Color.yellow)
}
Spacer()
}
}
.navigationBarHidden(true)
}
}
Looks like , but I want it to look like .
I've tried adding a negative padding to the top of the VStack (with .padding([.top], -95), and it visually works, but then I can't interact with the button by tapping it (I think it is behind the hidden navigation bar). I've tried setting the VStack's zIndex to 10000 to solve that, but it still didn't work. Is there a way for me to move the button up to the top while still making sure that the button recognizes when it is being tapped?
Add a navigationBarTitle before hiding your navigation bar:
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
NavigationButton(destination: Text("Button Clicked")) {
Text("Hello World")
.background(Color.yellow)
}
Spacer()
}
.navigationBarTitle(Text("Title")) // Add this line
.navigationBarHidden(true)
}
}
Add this modifier to your NavigationView edgesIgnoringSafeArea(.top).

Resources