SwiftUI - Using Navigation View and Sheets correctly - swiftui

Having issues with a NavigationView and Sheet. I have the below flow:
- ContentView: Has button that opens ContentView2 sheet
- ContentView2: Has NavigationLink with header that goes to ContentView3
- ContentView3: Has NavigationLink, no header, that directs users to ContentView2
However, when I set up the above flow, I end up getting stacked headers when users go back and forth between ContentView2 and ContentView3. How would I prevent this and only have 1 header when users go back and forth between the two views? Thanks!
struct ContentView: View {
#State var showSheet = false
var body: some View {
Button("Click"){
self.showSheet.toggle()
}
.sheet(isPresented: $showSheet) {
ContentView2()
}
}
}
struct ContentView2: View {
var body: some View {
NavigationView {
NavigationLink(destination: ContentView3()){
Text("Click Here")
}
.navigationBarTitle("Bar Title", displayMode: .inline)
}
}
}
struct ContentView3: View {
var body: some View {
NavigationLink(destination: ContentView2()){
Text("Click Here")
}
}
}

You need only one NavigationView in root, so here is corrected components
struct ContentView: View {
#State var showSheet = false
var body: some View {
Button("Click"){
self.showSheet.toggle()
}
.sheet(isPresented: $showSheet) {
NavigationView { // only here !!
ContentView2()
}
}
}
}
struct ContentView2: View {
var body: some View {
NavigationLink(destination: ContentView3()){
Text("Click Here")
}
.navigationBarTitle("Bar Title", displayMode: .inline)
}
}

Related

How hide navigation bar always back from any view directly using NavigationView?

I am using xcode-14.2 & minimum target version 14. I have three views ContentView, Welcome & `FundTransfer. Here is my case.
ContentView - Load first view & navigationBarHidden is working. When Welcome page button click it goes to Welcome page
Welcome view - When Fund Transfer button is clicked, it goes to FundTransfer view
FundTransfer - when Log out button is clicked, it goes to ContentView
It goeslike: ContentView-> FundTransfer-> ContentView
Problem: When it goes from FundTransfer view to ContentView it shows navigationBar. That means when back from FundTransfer view to ContentView shows navigationBar which was hidden at the first.
How do I hide navigation bar always back from any view directly to ContentView?
Here is my code:
ContentView:
struct ContentView: View {
#State private var showWelcome = false
#State var isNavigationBarHidden: Bool = true
var body: some View {
NavigationView {
VStack {
ScrollView {
VStack(alignment: .customCenter,spacing: 0){
VStack {
SubmitButton(action: {
self.showWelcome = true
}) {
Text("Welcome page")
}
}
NavigationLink(destination: Welcome(), isActive: $showWelcome) { EmptyView() }
}
}
}
.navigationBarTitle("") //this must be empty
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
}
Welcome View:
struct Welcome: View {
#State private var showFundTransfer = false
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
ScrollView {
VStack(alignment: .customCenter,spacing: 0){
VStack {
SubmitButton(action: {
showFundTransfer = true
}) {
Text("Fund Transfer")
}
}
NavigationLink(destination: FundTransfer(), isActive: $showFundTransfer) { EmptyView() }
}
}
.navigationBarHidden(true)
}
}
}
FundTransfer View:
struct FundTransfer: View {
#State var isNavigationBarHidden: Bool = true
#State private var logon = false
var body: some View {
VStack {
ScrollView {
VStack(alignment: .customCenter,spacing: 0){
SubmitButton(action: {
self.logon = true
}) {
Text("Log out")
}
}
}
NavigationLink(destination: ApplicationSwitcher(), isActive: $logon) { EmptyView() }.opacity(0)
}
.navigationBarHidden(true)
}
}
Please help me..
Add .navigationBarHidden(true) in NavigationLink also for eg:
NavigationLink(destination: ApplicationSwitcher()
.navigationBarHidden(true), isActive: $logon) { EmptyView() }.opacity(0)
In ContentView add "navigationBarHidden(true)" after the closure of NavigationView instead of VStack as mentioned below:
NavigationView {
...
}.navigationBarTitle("")
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)

SwiftUI - Navigation title background becomes transparent when VStack is visible

I'm running into an issue with the navigation title header in SwiftUI. It's a combination of a couple of things, as far as I can tell...
The main problem is that I'm trying to change the default background color of a view that contains a list. But when I use the tag .background(), the navigation title background becomes transparent. This only happens when there is a VStack on the view.
I have a simplify example code that shows the problem I'm facing:
ContentView:
import SwiftUI
struct ContentView: View {
#State var showButton: Bool
var body: some View {
VStack {
NavigationStack {
NavigationLink(
destination: SecondView(showButton: showButton),
label: {
Text("Take me to second view")
})
Toggle("VStack Visibile", isOn: $showButton)
.padding()
}
}
}
}
SecondView:
import SwiftUI
struct SecondView: View {
#State private var isButtonVisible: Bool = false
#State var showButton: Bool = true
var body: some View {
VStack {
List(0..<10) { _ in
Text("Hello World")
}
if showButton {
button
}
}
.navigationTitle("This is a title")
.background(Color(.systemCyan))
}
var button: some View {
Text("Something")
}
}
Please see below the resulting problem:
Issues / Suggestions:
ContentView
Have the NavigationStack outside the VStack
SecondView
Don't embed List inside a VStack
List is special and has special characteristics
Don't initialise #State property from outside, pass a binding instead
Code:
ContentView:
struct ContentView: View {
#State var showButton = true
var body: some View {
NavigationStack {
VStack {
NavigationLink(
destination: SecondView(showButton: $showButton),
label: {
Text("Take me to second view")
})
Toggle("VStack Visibile", isOn: $showButton)
.padding()
}
}
}
}
SecondView
struct SecondView: View {
#State private var isButtonVisible: Bool = false
#Binding var showButton: Bool
var body: some View {
List {
ForEach(0..<100) { _ in
Text("Hello World")
}
}
.safeAreaInset(edge: .bottom) {
if showButton {
HStack {
Spacer()
button
Spacer()
}
//I have added transparency, you can make it opaque if you want
.background(.cyan.opacity(0.8))
}
}
}
var button: some View {
Text("Something")
}
}
Try this if you don't want your list go under nav bar.
struct SecondView: View {
#State private var isButtonVisible: Bool = false
#State var showButton: Bool = true
var body: some View {
VStack {
List(0..<10) { _ in
Text("Hello World")
}
.padding(.top, 1)
if showButton {
button
}
}
.background(Color(.systemCyan))
.navigationTitle("This is a title")
}
var button: some View {
Text("Something")
}
}

How do I use a NavigationLink in SwiftUI?

I am new to Xcode and work on a Login Page.
I try to link all pages with each other but even if I saw these Code in a tutorial working it doesn't work for me.
I hope you can help me, I would appreciate it a lot?
In NavigationLink the order of parameters is very important
here is an example that may help you
struct Page1: View {
#Binding var GoToPage2: Bool
var body: some View {
VStack{
Button("Go To Page"){
GoToPage2 = true
print(GoToPage2)
}
NavigationLink(destination: Page2(), isActive: $GoToPage2){
EmptyView()
}
}
.navigationTitle("Page 1")
}
}
struct Page2: View {
var body: some View {
Text("page 2!")
.padding()
.navigationTitle("Page 2")
}
}
struct ContentView: View {
#State var GoToPage2 = false
var body: some View {
NavigationView{
VStack{
NavigationLink(destination: Page1(GoToPage2: $GoToPage2)){
Text("Signe In")
.padding()
.background(.regularMaterial)
.colorScheme(.dark)
.cornerRadius(12)
.font(.largeTitle.bold())
.foregroundColor(.primary)
}
}
.navigationTitle("App")
}
}
}
You can use NavigationLink in many different ways. Documentation here
struct ContentView: View {
#State var active: Bool = false
var body: some View {
NavigationView {
List {
NavigationLink(destination: EmptyView()) {
Label("Badge", systemImage: "app.badge")
}
NavigationLink("General", destination: EmptyView())
NavigationLink("About", destination: EmptyView(), isActive: $active)
}
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Text("View1")
// put the second view in destination in which you want to reach
// click in view2, this code will redirect from view1 to view2
NavigationLink(destination: View2()){
Text("View2")
}
}
}
}
}

Why is SwiftUI presented view displayed incorrectly?

I've created a SwiftUI "multiplatform" (iOS and macOS) app from the Xcode 12 beta 6 (12A8189n) app template.
My issue is that one of my views, AnotherView, is displaying incorrectly. Here's a gif showing the problem. Notice that AnotherView displays with the navigation stack already pushed to a non-existent view. Tapping the back button reveals the expected screen, however it is displayed only partially filling the expected area.
Here's the code:
TestNavigationApp.swift
import SwiftUI
#main
struct TestNavigationApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
#State private var presentingFirstView = false
var body: some View {
Button(action: { self.presentingFirstView = true }) {
Text("Present First View")
}
.sheet(isPresented: $presentingFirstView) {
FirstView(isPresented: $presentingFirstView)
}
}
}
FirstView.swift
import SwiftUI
struct FirstView: View {
#Binding var isPresented: Bool
var body: some View {
NavigationView {
EmbeddedView()
.navigationBarTitle("First View", displayMode: .large)
}
}
}
EmbeddedView.swift
import SwiftUI
struct EmbeddedView: View {
#State private var presentingAnotherView = false
var body: some View {
VStack {
Text("Embedded View")
Button(action: { self.presentingAnotherView = true }) {
Text("Present Another View")
}
}
.sheet(isPresented: $presentingAnotherView) {
AnotherView(isPresented: $presentingAnotherView)
}
}
}
AnotherView.swift
import SwiftUI
struct AnotherView: View {
#Binding var isPresented: Bool
var body: some View {
NavigationView {
Text("Another View")
.navigationBarTitle("Another View", displayMode: .large)
}
}
}
Anyway, not really sure what's happening here. Any suggestions appreciated.
Try to use navigation view style explicitly
var body: some View {
NavigationView {
Text("Another View")
.navigationBarTitle("Another View", displayMode: .large)
}.navigationViewStyle(StackNavigationViewStyle())
}

How to go to another view with button click

I have a button in my code and I have a file called LogindView.swift
I cannot get the code to open another view file when clicking on the button.
Can anybody give me an example on how to do it.
In my button action I have tried to write LogindView() but i just gives me a warning.
"Result of 'LogindView' initializer is unused"
Button(action: {
// Do action
LogindView()
}, label: {
//** Label text
Text("Logind")
.font(.headline)
.padding(.all)
.foregroundColor(Color.white)
})
.background(Color.blue)
You essentially have 3 options to transition between views depending on your needs.
First, you can use a NavigationView. This will provide a back button and will allow the user to go back. Note that there are some bugs currently when you don't put the NavigationLink inside of a List as per https://stackoverflow.com/a/57122621/3179416
import SwiftUI
struct MasterView: View {
var body: some View {
NavigationView {
List {
NavigationLink(destination: LoginView()) {
Text("Login")
}
}
.navigationBarTitle(Text("Master"))
}
}
}
struct LoginView: View {
var body: some View {
Text("Login View")
}
}
Second, you can present a modal using .sheet. This will present a modal that appears on top of the current view but it can be dismissed by the user by dragging it down.
import SwiftUI
struct MasterView: View {
#State var isModal: Bool = false
var body: some View {
Button("Login") {
self.isModal = true
}.sheet(isPresented: $isModal, content: {
LoginView()
})
}
}
struct LoginView: View {
var body: some View {
Text("Login View")
}
}
Third, you can just use an if statement to change the current view to your Login View like so
import SwiftUI
struct MasterView: View {
#State var showLoginView: Bool = false
var body: some View {
VStack {
if showLoginView {
LoginView()
} else {
Button("Login") {
self.showLoginView = true
}
}
}
}
}
struct LoginView: View {
var body: some View {
Text("Login View")
}
}
If you would like to animate this, so that the transition doesn't appear so abruptly, you can also do this:
import SwiftUI
struct MasterView: View {
#State var showLoginView: Bool = false
var body: some View {
VStack {
if showLoginView {
LoginView()
.animation(.spring())
.transition(.slide)
} else {
Button("Login") {
withAnimation {
self.showLoginView = true
}
}.animation(.none)
}
}
}
}
struct LoginView: View {
var body: some View {
Text("Login View")
}
}
You can use navigation link instead button
var body: some View {
VStack {
Text("Title")
.font(.headline)
Image("myimage").clipShape(Circle())
Text("mytext").font(.title)
NavigationLink(destination: AnotherView()) {
Image(systemName: "person.circle").imageScale(.large)
}
}
}