How to change master view width in SwiftUI split view on iPad - swiftui

Is it possible to increase the default width of the master view in SwiftUI split view implemented with NavigationView on iPad?
NavigationView {
masterView
detailView
}

To change the default width of the master view you may install SwiftUI-Introspect and add this to your NavigationView:
.introspectNavigationController { navigationController in
navigationController.splitViewController?.preferredPrimaryColumnWidthFraction = 1
navigationController.splitViewController?.maximumPrimaryColumnWidth = *preferred width*
}

Related

Swiftui nested navigation issue while using navigation link

My swiftui application structure looks like this
Navigation View (enclosing the landing view that is a list view )
On selection of a List item Navigation link directs to a Tab View with three tabs (default first tab)
When I use a sole standalone navigation link inside tab view screens to direct to another screen programatically, it navigates succesfully to the mentioned destination, but my binding doesn't work to come back to the previous screen.
Parent View
#State var showCameraPreviewView : Bool = false
ZStack{
Button("Show camera") {
showCameraPreviewView = true
}
NavigationLink(destination: CameraView(showCameraPreviewView: $showCameraPreviewView),isActive: $showCameraPreviewView){
EmptyView()
}
}
Child View
#Binding var showCameraPreviewView
Button("Assume capture success"){
self.showCameraPreviewView = false
}
Toggling showCameraPreviewView binding to false in the destination doesn't get me back to the current screen.
Looks straight forward, but doesn't work ! anything that I'm doing wrong ?
I can reproduce your issue, quite strange ... seems like the change of showCameraPreviewView is not accepted because the view is still visible. But I found a workaround with dismiss:
EDIT for iOS 14:
struct ChildView: View {
#Environment(\.presentationMode) var presentationMode
#Binding var show: Bool
var body: some View {
Button("Assume capture success"){
show = false
presentationMode.wrappedValue.dismiss()
}
}
}

Swift UI show modal sheet with tab bar visible

Is there anyway to keep the tab bar showing while presenting a modal / sheet view?
Here is a minimal failing example.
import SwiftUI
struct SheetView: View {
#Environment(\.dismiss) var dismiss
var body: some View {
Button("Press to dismiss") {
dismiss()
}
.padding()
}
}
struct Tab1: View {
#State private var showingSheet = false
var body: some View {
Button("Show Sheet") {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
SheetView()
}
}
}
struct MainView: View {
var body: some View {
TabView {
Tab1()
.tabItem {
Label("Tab 1", systemImage: "heart")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
MainView()
}
}
Thanks for answering my question in the comments.
Unfortunately the standard means of presenting views in SwiftUI is that they are truly modal – they capture the whole interaction context for the current scene, and you can’t interact with anything else until the modal is dismissed.
This is also the case for iPadOS. Even though a modal presented with .sheet on an iPad allows much more of the underlying view to be visible, you can’t interact with it until the sheet disappears. You can interact with different parts of the app by running two scenes side-by-side in split screen mode, but each half is a separate scene and any presented sheets are modal for that scene.
If you want one tab to optionally present a view over its usual content but still allow access to the tab view and its other tabs, that’s not a modal context and SwiftUI’s built-in sheet won’t work. You will have to implement something yourself - but I think that’s doable.
Rather than using .sheet, you could optionally add an overlay to your Tab1 view, using the same boolean state variable showingSheet. In this approach, the default dismiss environment variable won’t be available, so passing in the state variable as a binding value would be an alternative:
var body: some View
<main display>
.overlay(showingSheet ? Sheet1(presented: $showingSheet) : EmptyView())
You might also find that a ZStack works better than .overlay depending on what the contents of the tab view actually are.
You’ll definitely have a lot more structural work to do to make this work, but I hope you can see that it’s possible.

SwiftUI NavigationView detail view not shown

The following NavigationView contains a primary master and secondary detail view:
struct ContentView: View {
var body: some View {
NavigationView {
Text("Primary View")
.navigationTitle("Primary")
Text("Secondary View")
.navigationTitle("Secondary")
}
}
}
When used with an iPad in any orientation everything works as expected. The primary view is shown in the sidebar and the secondary view is shown in the main content area:
When used on an iPhone the primary view is displayed and there seems to be no way to access the secondary view:
What is the correct way to set up a master/detail NavigationView on the iPhone?
If all you want to show is the secondary view when horizontal size is compact, why not just show it? The master view is there to provide selections for the user for navigating.
Otherwise, you don't have a NavigationLink and that is what will push the secondary view when horizontal size is compact.
NavigationView {
VStack {
NavigationLink("Choice 1", Text("Choice 1"))
...
}
Text("Secondary View").navigationTitle("Secondary")

Does TabView miss navigation clicks while redrawing?

I have a vanilla TabView, an #ObservedObject, and a background task running which periodically updates the #Published field of the #ObservedObject.
I've noticed that when the background task runs more frequently, and generates more changes to the #ObservedObject, the navigation tabs on the TabView become less responsive - they 'miss' taps. If I tap two or three times, I can normally change the view. The more frequent the background updates, the more often taps are 'missed'.
So I'm wondering if the TabView somehow fails to notice taps while it is redrawing, or something like that?
Any insights?
import Foundation
import SwiftUI
struct ContentView2: View {
enum Tabs {
case main
case audio
case preferences
}
#State var tab = Tabs.preferences
#ObservedObject var appState = Globals.appState
var body: some View {
TabView(selection: $tab) {
MainView()
.tabItem {
Image(systemName: "video.fill")
Text("Main")
}.tag(Tabs.main)
AudioControlView()
.tabItem {
Image(systemName: "speaker.fill")
Text("Audio")
}.tag(Tabs.audio)
PreferenceView()
.tabItem {
Image(systemName: "gear")
Text("Prefs")
}.tag(Tabs.preferences)
}
}
}
Found the problem...
The TabView doesn't need #ObservedObject var appState = Globals.appState because the TabView itself doesn't depend on the #Published fields.
Instead, the individual tabs (MainView() etc. ) need to observe.
So what was happening was that the TabView was being unnecessarily recomputed and redrawn for every change. Removing this line fixed everything.

How do I create a simple app with a side bar in SwiftUI?

I've had my app inside a NavigationView using the StackNavigationViewStyle style for some time with no problems. Recently I wanted to add a sidebar to it though, so I thought I should try using the DoubleColumnNavigationViewStyle style for this. At the moment I can kind of make it work but it has some quirks:
If I am in a subview, and I try to slide back into its parent view, sliding back always brings the side bar into view instead of taking me back into the parent view which is what I would expect. Now matter how deep into my view hierarchy I am. (If you use the default Notes app and select View as a Gallery, that is exactly the way I expect my app to work like).
Much less important but annoying nonetheless is that if I press the back button, the nice animations of the sliding < back buttons into/out of view I got when I used StackNavigationViewStyle no longer happen. The buttons work fine but the animations are much worse now.
Here is a sample minimum app and a video to show what I mean:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Sidebar")
MainView()
}
}
}
struct MainView: View {
var body: some View {
Text("Main View")
NavigationLink(destination: Text("Sub View")) {
Text("Go to Sub View")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Thanks!