How to use Paged TabView inside ScrollView in SwiftUI? - swift

Context
I am having a SwiftUI ScrollView and would like to use Paged TabViews inside to display data. However, this concludes in strange behaviour of the View collapsing to zero height.
Code
struct SomeView: View {
var body: some View {
NavigationView {
ScrollView {
TabView {
Text("View A")
Text("View B")
Text("View C")
}
.tabViewStyle(.page)
}
}
}
}
Questions
How can I achieve my goal of using a Paged TabView inside a larger ScrollView without it collapsing to zero height?
I read in the documentation, that .tabViewStyle(.page) is not available on macOS. Is there any workaround to still use Paged TabViews on macOS?

Related

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

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()

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

NavigationView height irregular swiftui

I have a NavigationView and added a title. The problem is it looks weird when I run it.
var body: some View {
NavigationView {
Form {
Section {
Text("Hello World")
}
}
.navigationBarTitle("SwiftUI", displayMode: .inline)
}
}
The image looks weird. How can I make the navigation height look better just like UIKIt Navigation Bar
You have a double-nested NavigationView.
The view that you are showing in your example is already being presented from a NavigationView, so you don't need to create an additional view.
This is because the navigation view context is preserved when you use a NavigationLink.
Try removing it:
var body: some View {
Form {
Section {
Text("Hello World")
}
}
.navigationBarTitle("SwiftUI", displayMode: .inline)
}

How to disable vertical scroll in TabView with SwiftUI?

I have set up a TabView in my application, so that I can swipe horizontally between multiple pages, but I also have an unwanted vertical scroll that may appear, with a bounce effect so. How can I disable this vertical scroll?
My code:
struct ContentView: View {
#State private var currentTabIndex: Double = 0
var body: some View {
VStack {
TabView(selection: $currentTabIndex) {
Text("Text n°1")
.tag(0)
Text("Text n°2")
.tag(1)
}
.border(Color.black)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}
I had this same problem. It's not an exact solution, but you can turn off bouncing on scrollviews (which is used within a TabView). And as long as the items within the TabView are not larger than the TabView frame, it should act as if you disabled vertical scrolling.
I would call it either .onAppear or in your init function:
.onAppear(perform: {
UIScrollView.appearance().bounces = false
})
Note: this disables the bouncing on ALL scrollviews across your app... So you may want to re-enable it .onDisappear.
Still an issue with Xcode 12.4.
I managed to workaround that by wrapping the TabView within a ScrollView and using the alwaysBounceVertical property set to false, as follow:
ScrollView(.horizontal) {
TabView {
///your content goes here
}
.tabViewStyle(PageTabViewStyle())
}
.onAppear(perform: {
UIScrollView.appearance().alwaysBounceVertical = false
})
.onDisappear(perform: {
UIScrollView.appearance().alwaysBounceVertical = true
})
I actually came across this because I saw this effect in a tutorial but couldn’t replicate it on iOS 15.2. However, I managed to replicate it on iOS 14.4 on another simulator side by side. So I guess this behaviour is disabled or fundamentally changed in the newer iOS.
Demonstration