htpA here!
I am a newbie of SwiftUI programming and I am just trying to add a navigation title for macOS like in iOS. I tried many things but it didn't seem to be working. I hope anyone would answer it quickly.
Here's my code
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List {
Spacer()
NavigationLink(destination: LatestEpisodes()) {
Menu1()
}
.frame(minWidth: 110)
.frame(maxWidth: 110)
}
Text("Content")
}
.navigationTitle("Hello!")
.frame(minWidth: 900)
.listStyle(SidebarListStyle())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Menu1: View {
var body: some View {
VStack {
Image(systemName: "1.circle.fill")
Text("Menu1")
}
.frame(width: 90, height: 90)
.padding(10)
}
}
I have a VSplitView in my app and I would like the position to be saved and restored automatically by the user defaults. Normally I would do this by providing an autosaveName for the split view either programmatically or in the XIB.
How do I accomplish that in SwiftUI using a VSplitView?
struct ContentView: View {
var body: some View {
VSplitView {
Text("Top View")
.padding()
.frame(maxWidth:.infinity, maxHeight: .infinity)
Text("Bottom View")
.padding()
.frame(maxWidth:.infinity, maxHeight: .infinity)
}
// I expected something like:
//.autosaveName("MainSplitView")
}
}
been searching for this everywhere and can't find anything around this, I believe is a bug, maybe is not.
I need NavigationView with .navigationViewStyle(.stack) to have it stacked on the iPad and make it look the same as the iphone, now suppose you have this view:
import SwiftUI
struct ContentView: View {
#State var isShowingProfile = false
#State var isNavigationViewShowing = true
var body: some View {
if isNavigationViewShowing {
NavigationView {
VStack {
Button("Simple view") {
isNavigationViewShowing = false
}
.padding()
Button("Profile navigation") {
isShowingProfile = true
}
.padding()
NavigationLink(
destination: ProfileView(),
isActive: $isShowingProfile
) {
EmptyView()
}
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
)
.background(Color.gray)
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
} else {
VStack {
Button("Show NavigationView"){
isNavigationViewShowing = true
}
.padding()
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
).background(Color.yellow)
}
}
}
struct ProfileView: View {
var body: some View {
Text("This is a profile")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Well this just show this 3 simple views:
The navigationView when you start
The Profile view if you tap on "Profile navigation"
Finally the Simple view which is trigger by the conditional state pressing "Simple view"
Up to here is all fine and good.
The problem is when navigate to the "Simple view" and then tap "Show NavigationView" to navigate back to the NavigtionView.
The app opens the first view (NavigationView), but the NavigationView ignores the .navigationBarHidden(true) and just show a big empty space on the top. In fact, it would ignore things like .navigationBarTitleDisplayMode(.inline) and just show the large version of the navigationBar
This is working correctly in all iOS 14.x, but on iOS 15.0 seems broken. The behaviour continues to be the same on iOS 15.1 beta.
Any idea whats going on? I'm not really interested in changing the conditionals on the view, because real life app is more complex.
Also, I tried ViewBuilder without any success. And if I take out .navigationViewStyle(.stack) it works all fine on iOS 15, but then the view on the iPad is with the side menu.
Thanks a lot for any tip or help, you should be able to reproduce in simulator and real device.
Video of the explained above
I think the better solution all around is to not have the NavigationView be conditional. There is no reason your conditional can't just live in the NavigationView. You just don't ever want the bar to show. Therefore, this code would seem to meet the requirements:
struct ContentView: View {
#State var isShowingProfile = false
#State var isNavigationViewShowing = true
var body: some View {
NavigationView {
Group {
if isNavigationViewShowing {
VStack {
Button("Simple view") {
isNavigationViewShowing = false
}
.padding()
Button("Profile navigation") {
isShowingProfile = true
}
.padding()
NavigationLink(
destination: ProfileView(),
isActive: $isShowingProfile
) {
EmptyView()
}
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
)
.background(Color(UIColor.systemGray6))
} else {
VStack {
Button("Show NavigationView"){
isNavigationViewShowing = true
}
.padding()
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
).background(Color.yellow)
}
}
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
}
}
I used Group simply to put the .navigationBarHidden(true) in the correct place so the code would compile.
Is this the behavior you are looking for?
import SwiftUI
struct ContentView: View {
#State private var isShowingProfile = false
#State private var showSimple = false
var body: some View {
NavigationView {
VStack {
Button("Simple view") {
showSimple = true
}
.padding()
Button("Profile navigation") {
isShowingProfile = true
}
.padding()
NavigationLink(destination: ProfileView(), isActive: $isShowingProfile) {
EmptyView()
}
}
.fullScreenCover(isPresented: $showSimple, onDismiss: {
print("Dismissed")
}, content: {
SimpleView()
})
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
)
.background(Color.gray)
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
}
}
struct ProfileView: View {
var body: some View {
Text("This is a profile")
}
}
struct SimpleView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
Button("Show NavigationView") {
presentationMode.wrappedValue.dismiss()
}
.padding()
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
).background(Color.yellow)
}
}
I am working on a SwiftUI view. When using the NavigationView inside the TabView the app works as expected.
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
Text("A")
.navigationBarTitle("Nav A")
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
NavigationView {
Text("B")
.navigationBarTitle("Nav B")
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
//.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) // this line breaks the view
}
}
As soon as I uncomment .tabViewStyle(...) the view does not work as expected. Any ideas why? The text is not visible anymore. The navigation does not seem to be correct either.
Try moving the NavigationView outside the TabView:
struct ContentView: View {
#State var selection = 1
var body: some View {
NavigationView {
TabView(selection: $selection) {
Text("A").tag(1)
Text("B").tag(2)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.navigationTitle(selection == 1 ? "A" : "B")
}
}
}
It seems like the NavigationView defaults to presenting as a primary/detail display.
You can force it to work like a normal navigation stack with the modifier .navigationViewStyle(StackNavigationViewStyle())
Here it is in your code:
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
Text("A")
.navigationBarTitle("Nav A")
}
.navigationViewStyle(StackNavigationViewStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
NavigationView {
Text("B")
.navigationBarTitle("Nav B")
}
.navigationViewStyle(StackNavigationViewStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
I made a simple app to illustrate the issue. I have a custom Tab view, however when I click on text field and open the keyboard and my navigation tabs is being pushed up as well. I would like for navigation to be not visible (as one would expect for any app).
This image illustrates the problem:
This issue does not happen if I use native TabView, however I would like to use custom tabs. Does anyone figured out how to deal with it? Providing the code below.
struct ContentView: View {
#State var menu = 0
var body: some View {
VStack {
VStack {
if menu == 0 {
FirstPage()
} else if menu == 1 {
Text("all is good")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
CustomTabs(menu: $menu)
}
}
}
struct CustomTabs: View {
#Binding var menu: Int
var body: some View {
HStack {
Spacer()
Text("Nav1")
.onTapGesture{
self.menu = 0
}
Spacer()
Text("Nav2")
.onTapGesture{
self.menu = 1
}
Spacer()
}
.padding()
.background(Color(.red))
}
}
struct FirstPage: View {
#State var mood: String = ""
var body: some View {
VStack {
Text("How are you?")
TextField("answer textfield", text: $mood)
}
}
}
A possible solution/work-around would be to embed the CustomTabs in a VStack with a Spacer which pushes the tabs down even when the keyboard appears and then put this Stack in front of your view via ZStack.
struct ContentView: View {
#State var menu = 0
var body: some View {
ZStack {
VStack {
if menu == 0 {
FirstPage()
} else if menu == 1 {
Text("all is good")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
VStack {
Spacer(minLength: UIScreen.main.bounds.height - 70)
CustomTabs(menu: $menu)
.frame(height: 70)
}
}
}
}
For simplicity I just decided to set the tabs height to 70. A more beautiful solution would be to use GeometryReader.