iPad NavigationSplitView - Detect if sidebar is a slide over - ios

Overview
I have a 3 column NavigationSplitView
On iPad I would like to detect if the sidebar (red) / content (green) is a slide over
I don't want to rely on orientation as it is possible to have multiple apps side by side and that can change the view size
Questions:
On iPad, how can I detect if sidebar (red) / content (green) is a slide over?
Or is there an alternate approach?
Code
struct ContentView: View {
#State private var splitViewVisibility = NavigationSplitViewVisibility.automatic
var body: some View {
NavigationSplitView(columnVisibility: $splitViewVisibility) {
Color.red
} content: {
Color.green
} detail: {
Color.blue
}
}
}
Screenshot
Slide over
Not Slide Over

Related

SwiftUI how to force a divider for navigation bar in NavigationView

My app has simple navigation logic using navigation view. I use the inline style navigation bar:
mainView
.navigationBarTitleDisplayMode(.inline)
I notice that the navigation bar's divider is missing for the root view. And it appears when I scroll up the content a bit.
This first screenshot shows the initial state (without nav bar divider):
This second screenshot shows the state when I scroll up the content a bit, and it shows nav bar divider:
Is it possible to always show the divider without scrolling?
I think you can work around by adding a manual Divider and ScrollView under VStack so that the divider will appear beneath the navigation bar
//
// testUI.swift
// DDStore (iOS)
//
// Created by belal medhat on 19/02/2022.
//
import SwiftUI
struct navTitleBar: View {
var body: some View {
NavigationView {
// main navigationView
VStack(){
// vstack to add the divider and under it the scrollview
Divider()
ScrollView(){
Text("Hello, World!")
}.navigationBarTitleDisplayMode(.inline).navigationTitle("Title")
}
}
}
}
struct testUI_Previews: PreviewProvider {
static var previews: some View {
navTitleBar()
}
}

Keyboard safe area wrong for iPad in multitasking Slide Over (SwiftUI/UIKit)

I've got a view with content on the bottom edge, which gets partially obscured by the keyboard when the app is in Slide Over. This isn't the case in side-by-side multitasking or when the app is full screen.
All other configurations are fine:
Side-by-side, with keyboard:
Slide over, without keyboard:
Here's the example view code:
struct ContentView: View {
#State private var text = ""
var body: some View {
VStack {
TextField("", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle())
Spacer()
Text("Hello, world!")
.font(.title)
}
}
}
I've noticed this issue in SwiftUI lifecycle apps, UIKit lifecycle apps, across different iOS versions (including iOS 14) and on all iPad sizes.
I've seen solutions that check the UIDevice.current.userInterfaceIdiom and the window bounds to check if the app is in Slide Over and adjust the UI, but I'm using SwiftUI and I'd like to avoid this kind of hack. Any advice on how to deal with this?

How can I make a SwiftUI List row background color extend the full width, including outside of the safe area

In a SwiftUI List, how can I make a list row background (set via .listRowBackground()) extend the full width of the view, even under the safe area? E.g. when running in landscape on a wide iPhone (iPhone 12 Pro Max, for example). Currently, the cell appears white on the far left of the cell until the start of the safe area.
Example code:
struct ContentView: View {
var body: some View {
List {
Text("Test")
.listRowBackground(Color(.systemGray3))
}.listStyle(GroupedListStyle())
}
}
This produces a UI as shown below. I would like the grey background of the cell to extend the full width of the device.
I've tried adding .edgesIgnoringSafeArea(.all) to the Text but it makes no difference.
The answer is to put .edgesIgnoringSafeArea([.leading, .trailing]) on the background Color itself, rather than the list item.
struct ContentView: View {
var body: some View {
List {
Text("Test").listRowBackground(
Color(.systemGray3).edgesIgnoringSafeArea([.leading, .trailing])
)
}.listStyle(GroupedListStyle())
}
}

Change background color of View inside TabView having NavigationView and ScrollView in SwiftUI

I want to build a TabView with 4 tabs having collection views in it. Below is my code of one tab named 'Gallery'.
var body: some View {
NavigationView {
ScrollView {
GridStack(rows: 3, columns: 2) { row, column, totalColumn in
CardView(card: self.cards[(row * totalColumn) + column])
}.padding().background(Color.red)
}
.navigationBarTitle("Gallery")
}
}
When I give background color for ScrollView, scrolling is not working for NavigationView largeTitle. How can I achieve this, I want to give red color for full view's background? What if I need to achieve this same backgorund color for all tabs?
Here is possible approach (scroll view is not broken in such case)
NavigationView {
GeometryReader { gp in
ScrollView {
ZStack(alignment: .top) {
Rectangle().fill(Color.red) // << background
// ... your content here, internal alignment might be needed
}.frame(minHeight: gp.size.height)
}
.navigationBarTitle("Gallery")
}
}

SwiftUI show/hide title issues with NavigationBar

I have the following code construct which gives me a lot of trouble:
//Main View
struct ContentView: View {
var body: some View {
NavigationView{
ZStack(alignment: .center){
CarouselBuilder()
ProfileInvoke().navigationBarTitle("").navigationBarHidden(true)
}
}
}
}
//Carousel filled with Cards from a DB
...code irrelevant for my problem
//Profile Invoke -> Invokes a slide out menu called Menu that has NavigationLinks in it
struct Menu: View {
var body: some View {
ZStack{
VStack(alignment: .center){
MenuButton(buttonText: "Settings", buttonCallView: AnyView(SettingsView() ))
MenuButton(buttonText: "My Favourites", buttonCallView: AnyView(MyFavouritesView()))
MenuButton(buttonText: "Sign Out", buttonCallView: AnyView(SignOutView()))
}.frame(width: UIScreen.main.bounds.width/1.2,alignment: .top)
}
}
}
//MenuButtons are basic NavigationLinks linking to certain Views given as argument when calling them
I now do wrap the ZStack in the Main View in a NavigationView which I need to to in order for the NavigationLinks to work. I also have to do this on this "top" level as I need the new View that will be invoked by the links in the slide out menu to take the entire screen and not only the width the slide out view is being displayed.
My issue is now that I certainly do not want the navigation bar to take up space in the main view. For this I set the hidden attribute for it to true. This tho, carries through the entire app and also disables the navigation view in the subviews linked to by the buttons in the menu. Which gives me no way of going back.
My question would be:
1) Is there a more elegant way of doing all of this?
2) How can I re-invoke the navigation bar in sub views? (Setting the hidden navigation bar attribute on them back to false did not work.
Below is a possible approach to hide navigation bar in root view and show in child subviews. The only needed modifications is in root view.
Tested with Xcode 11.4 / iOS 13.4
Here is a root only, child sub-views are regular and do not require special code for this case. See important notes inline.
struct RootNavigationView: View {
#State private var hideBar = true // << track hide state, and default
var body: some View {
NavigationView {
VStack {
Text("I'm ROOT")
Divider()
NavigationLink("Goto Child", destination: NextChildView(index: 1))
.simultaneousGesture(TapGesture().onEnded {
self.hideBar = false // << show, here to be smooth !!
})
}
.navigationBarHidden(hideBar)
// .navigationBarTitle("Back to Root") // << optional
.onAppear {
self.hideBar = true // << hide on back
}
}
}
}

Resources