Navigationbar title is inline on pushed view, but was set to large - swift

I want a large title in the navigationbar on a pushed view in SwiftUI and an inline title on the parent view.
When the parent navigation bar display mode is not set, it works:
Working without display mode on parent
But when I set the display mode in the parent view to inline, the title on the second screen is inline, instead of large. You can drag the list and the title will stay large. (You can see a small example in the code below)
With display mode to inline on the parent, the child is also inline.
Here is a small example:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DestinationView()) {
Text("Next Screen")
}
.navigationBarTitle("Start screen", displayMode: .inline)
}
}
}
struct DestinationView: View {
var body: some View {
ScrollView {
VStack{
ForEach((1...10), id: \.self) {
Text("\($0)")
}
}
}
.navigationBarTitle("Second screen", displayMode: .large)
}
}
There are several post with similar questions:
https://www.reddit.com/r/iOSProgramming/comments/g2knmp/large_title_collapses_after_a_push_segue/
-> Same problem but with UIKit and we don't have prefersLargeTitles in SwiftUI.
Large title doesn't appear large
-> Same problem with UIKit and marked as answered with preferesLargeTitles.
Navigation bar title stays inline in iOS 15
-> Here was a fix from apple side, but it was a back navigation

just place .navigationViewStyle(.stack) in NavigationView in ContentView()

Related

SwiftUI: List inside TabView inside NavigationView breaks animation

I want to have a TabView inside a NavigationView. The reason is that I am showing a List inside the TabView. When a user taps on an item in the list, the list uses a NavigationLink to show a detailed screen.
The problem is that the navigationBarTitle is now broken. It does not animate when the user scrolls through the items (sometimes). I don't want to wrap my NavigationView inside the TabView, since that will always show the TabView. I don't want it.
This is the reproduction code. If you run this in the simulator, the animation will break when switch a few times between the tabs and you scroll through the list. You will see that the navigation bar will remain where it is, without the animation.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
TestView()
.tabItem {
Image(systemName: "person.3")
}
TestView()
.tabItem {
Image(systemName: "person.2")
}
}
.navigationTitle("Test")
.navigationViewStyle(.stack)
}
}
}
struct TestView: View {
var body: some View {
List {
Text("test")
}
.listStyle(.plain)
}
}

SwiftUI NavigationView nested in PageTabView wrong aligned on first appear

The NavigationViews inside my PageTabView are wrong aligned on first appear.
When i scroll to another page on my PageTabView and go back to the first page, the alignment is correct.
The content of the navigationview (red) is beneath the navigationbar on first appear.
Image of first appearance of the NavigationView
Image of the second appearance of the NavigationView
struct ContentView: View {
var body: some View {
TabView {
ForEach(0..<3) { index in
NavigationView {
Color.red
.navigationTitle("\(index). Page")
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
.tabViewStyle(.page)
}
}
Edit:
I want to build the layout of the rooms tab in the apple home app in compact mode. Therefore the TabView in the code above gets wrapped in another tabview without the pagetabviewstyle modifier.
This works, but the same extracted problem in the code above happens.
var body: some View {
NavigationView {
TabView {
ForEach(0..<3) { index in
Color.red
.navigationTitle("\(index). Page")
}
}
.tabViewStyle(.page)
}
}
Just moved NavigationView outside, it fixed the problem

SwiftUI: showing keyboard in a tab view adds a weird space below second tab view

This sounds a bug in SwiftUI's NavigationView and TabView, when I have a TabView with (let's say) 2 tabs, the first tab has a TextField and the second tab has a NavigationView, follow these steps to produce the bug:
show the keyboard by tapping on the text field.
press on the "Return" button to hide the keyboard.
go to tab 2.
notice the weird bottom added space below the view, which approximately equals the height of the keyboard.
-Note1: if you do any of the following the bug won't be reproduced:
once the app launches, open tab 2, return to tab 1 and show the keyboard.
remove NavigationView from tab 2
show the keyboard one more time in tab 1
Note2:
I use GeometryReader in tab 2 to show the whole view area by a yellow color.
working code sample (just copy-paste it to try):
struct ContentView: View {
var body: some View {
TabView {
View1()
.tabItem { Text("View1") }
.tag(1)
View2()
.tabItem { Text("View2") }
.tag(2)
}
}
}
struct View1: View {
#State private var myText = ""
var body: some View {
VStack {
Text("this is view 1")
TextField("Enter Value", text: $myText)
}
}
}
struct View2: View {
var body: some View {
NavigationView {
GeometryReader { reader in
Text("this is view 2")
.onAppear{
print("view 2 on appear")
}
}
.background(Color.yellow)
}
}
}
screenshot:
Is there a way to workaround this problem without having to remove the NavigationView, I tried every possible solution but couldn't a find a clue to avoid it ?

SwiftUI navigationView within Modal 'pushing' view down

I currently have a modal view in SwiftUI that contains a series of NavigationLinks to different views. However, when I go to one of the other views it pushes all the content down leaving a empty forehead at the top of the view. How do I fix this?
I have included an example screenshot below.
To further clarify, there is a main view with a button that opens a Modal view. This modal contains a navigation view with a series of NavigationLink Buttons. When opening the navigation links within the modal, that is when the view is pushed down.
You have a large navigation bar, try to set navigationBar displayMode to .inline
.navigationBarTitle(Text(""), displayMode: .inline)
This probably happens because the view you push to from the NavigationView is also wrapped in a NavigationView.
struct SettingsView: View {
var body: some View {
NavigationView {
NavigationLink(destination: IAPView()) {
Text("In App Purchase")
}
}
}
}
You probably have this in the IAPView()
struct IAPView: View {
var body: some View {
NavigationView { <-- this is causing it
// your buttons here
}
}
}
You still have the default navigation bar space in your view. You need to add both these two view modifiers.
.navigationBarTitle("")
.navigationBarHidden(true)

SwiftUI Navigation through multiple screens

I'm a bit confused on how navigation works in SwiftUI. Does only the view starting the navigation need a NavigationView? I have one view with a NavigationView that has a NavigationLink to a second view. The second view then has a NavigationLink to a third and final view.
However, when my second view navigates to my third view, I get this message in the logs:
unbalanced calls to begin/end appearance transitions for <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7f85d844bf90>.
I don't know if I'm handling navigation through multiple screens correctly and I'm getting some really odd behavior where pressing Next on my second screen takes me back to my first somehow...
//This is the link in my first view, my seconds link is the same except it does to my next step and the tag is different
NavigationLink(
destination: PasswordView(store: self.store),
tag: RegisterState.Step.password,
selection: .constant(store.value.step)
)
Navigation is a little bit tricky in SwiftUI, after creating one navigationview you don't need to create again in your 2nd or 3rd view. I am not sure how you creating it firstly. Here is an example how navigation is working.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: SecondView()) {
Text("Show Second View")
}.navigationBarTitle("FirstView", displayMode: .inline)
}
}
}
}
struct SecondView: View {
var body: some View {
NavigationLink(destination: ThirdView()) {
Text("Show Third view")
}.navigationBarTitle("SecondView", displayMode: .inline)
}
}
struct ThirdView: View {
var body: some View {
Text("This is third view")
.navigationBarTitle("ThirdView", displayMode: .inline)
}
}