Dismiss modal view from another view in swiftUI - ios

I want to dismiss a modal view in SwiftUI, but I just can't
This is my code:
ContentView:
import SwiftUI
enum Destination {
case modal
}
struct ContentView: View {
#Environment(\.presentationMode) var presentationMode
#State private var showModal = false
var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: false) {
VStack{
SubscribeButtonView(buttonTitle: "Modal", destination: .modal, showModal: $showModal)
.padding(.top, 50)
.padding(.leading, 30)
.padding(.trailing, 30)
Spacer()
}
}
.navigationBarTitle(Text("Menu"))
}
}
}
The ModalView:
import SwiftUI
struct ModalView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading) {
Spacer()
SaveButtonView(origin: .modal)
Spacer()
}
.padding(.leading, 20)
.padding(.trailing, 20)
}
.navigationBarTitle("Modal")
.navigationBarItems(trailing: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Cancel")
})
}
}
}
The SubscribeButtonView:
import SwiftUI
struct SubscribeButtonView: View {
#Environment(\.presentationMode) var presentationMode
var buttonTitle: String
var destination: Destination
#Binding var showModal: Bool
var body: some View {
Button(action: {
self.showModal.toggle()
}) {
HStack {
Image(systemName: "plus.circle")
.font(.body)
Text(buttonTitle)
}
}.sheet(isPresented: $showModal) {
if self.destination == .modal {
ModalView()
}
}
.padding()
}
}
The SaveButtonView:
import SwiftUI
struct SaveButtonView: View {
#Environment(\.presentationMode) var presentationMode
var origin: Destination
var body: some View {
Button(action: {
//THIS IS NOT WORKING
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Text("Save")
}
}
.padding()
}
}
I tried to create a really simple new project with just one state to call the modal, the menu, the modal and the two buttons and it worked just fine. I can't understand why it isn't working in the code above
Did anyone have this same issue?

You are supposed to bind the presentationMode from ModalView.
struct SaveButtonView: View {
//#Environment(\.presentationMode) var presentationMode
#Binding var presentationMode : PresentationMode
var origin: Destination
var body: some View {
Button(action: {
//THIS IS NOT WORKING
self.$presentationMode.wrappedValue.dismiss()
}) {
HStack {
Text("Save")
}
}
.padding()
}
}
struct ModalView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading) {
Spacer()
SaveButtonView( presentationMode: self.presentationMode, origin: .modal)
Spacer()
}
.padding(.leading, 20)
.padding(.trailing, 20)
}
.navigationBarTitle("Modal")
.navigationBarItems(trailing: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Cancel")
})
}
}
}

Related

Why The Navigation View doesn't show up using SwiftUI?

I have the following files and I don't know why the navigation bar is not showing.
In the first file I am using NavigationView before ContentView().
File 1:
import SwiftUI
#main
struct TwitterCloneApp: App {
var body: some Scene {
WindowGroup {
NavigationView{
ContentView()
}
}
}
}
In second file I am using MainTabView(), but there is no navigation bar space.
File 2
import SwiftUI
struct ContentView: View {
#State private var showMenu = false
var body: some View {
ZStack(alignment: .topLeading){
MainTabView()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Here it is the MainTabView.
File 3:
import SwiftUI
struct MainTabView: View {
#State private var selectedIndex: Int = 0
var body: some View {
TabView(selection: $selectedIndex){
FeedView()
.onTapGesture {
self.selectedIndex = 0
}
.tabItem{
Image(systemName: "house")
}.tag(0)
ExploreView()
.onTapGesture {
self.selectedIndex = 1
}
.tabItem{
Image(systemName: "magnifyingglass")
}.tag(1)
NotificationsView()
.onTapGesture {
self.selectedIndex = 2
}
.tabItem{
Image(systemName: "bell")
}.tag(2)
MessagesView()
.onTapGesture {
self.selectedIndex = 3
}
.tabItem{
Image(systemName: "envelope")
}.tag(3)
}
}
}
struct MainTabView_Previews: PreviewProvider {
static var previews: some View {
MainTabView()
}
}
There is no space for the navigation bar.
There are several things wrong with the code you've posted:
Each sub-view within a TabView should have its own NavigationView.
There shouldn't be a NavigationView at the top level
Each top-level view within a NavigationView should have a .navigationTitle
The tapGesture isn't needed to switch between tabs
so you should end up with
struct TwitterCloneApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
and
struct MainTabView: View {
#State private var selectedIndex: Int = 0
var body: some View {
TabView(selection: $selectedIndex){
NavigationView {
FeedView()
.navigationTitle("Feed")
}
.tabItem{
Image(systemName: "house")
}.tag(0)
NavigationView {
ExploreView()
.navigationTitle("Explore")
}
.tabItem{
Image(systemName: "magnifyingglass")
}.tag(1)
NavigationView {
NotificationsView()
.navigationTitle("Notifications")
}
.tabItem{
Image(systemName: "bell")
}.tag(2)
NavigationView {
MessagesView()
.navigationTitle("Messages")
}
.tabItem{
Image(systemName: "envelope")
}.tag(3)
}
}
}

When i am Switching the Tab in Swiftui Every Time new View is showing and my previous View was Vanished can anyone fix this?

When i am Switching the Tab in Swiftui Every Time new View is showing and my previous View was Vanished.I have Tried Userdefaults also but not working.
import SwiftUI
struct HomeView: View {
#State var selectedTabs = "house"
var body: some View {
ZStack(alignment: .bottom) {
Color("LightTabColor")
.edgesIgnoringSafeArea(.all)
VStack{
CardView(selectedTab: selectedTabs)
CustomTabBar(selectedTab: $selectedTabs)
.padding(.bottom)
}
}.onAppear {
let selectedTab = UserDefaults.standard.string(forKey: "selectedTabs")
if let selectedTab = selectedTab {
self.selectedTabs = selectedTab
}
}.onDisappear {
UserDefaults.standard.set(self.selectedTabs, forKey: "selectedTabs")
}
}
}
struct CardView: View {
var selectedTab: String
var body: some View {
ZStack{
Color("LightTabColor")
.cornerRadius(25)
.frame(maxWidth: .infinity,maxHeight: .infinity)
.padding(10)
.shadow(radius: 30)
VStack {
// Show the appropriate view based on the selected tab
switch selectedTab {
case "gear.circle":
NewAI()
case "house":
ImageAI()
case "message":
ChatAI()
default:
ImageAI()
}
Spacer()
}
.padding(.leading,10)
.padding(.bottom,10)
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}

Navigation not working in SwiftUI - Pop to a specific view

I am trying to pop to a specific view using the isActive binding of NavigationLink of SwiftUI. Here is my code:
struct Root: View
{
#Environment(\.dismiss) var dismissValue: DismissAction
#State var rootToView1Navigattion: Bool = false
var body: some View
{
HStack
{
NavigationLink(isActive: $rootToView1Navigattion) {
View1()
} label: {
EmptyView()
}
Button {
dismissValue()
} label: {
Text("Go Back")
.font(.title3)
.padding()
.background(Color.yellow)
}
Button {
rootToView1Navigattion = true
} label: {
Text("Go Forward")
.font(.title3)
.padding()
.background(Color.green)
}
}
.navigationTitle(String(describing: Self.self))
}
}
struct View1: View
{
#Environment(\.dismiss) var dismissValue: DismissAction
#State var view1ToView2Navigation: Bool = false
var body: some View
{
HStack
{
NavigationLink(isActive: $view1ToView2Navigation) {
View2(view1ToView2NavBinding: $view1ToView2Navigation)
} label: {
EmptyView()
}
Button {
dismissValue()
} label: {
Text("Go Back")
.font(.title3)
.padding()
.background(Color.yellow)
}
Button {
view1ToView2Navigation = true
} label: {
Text("Go Forward")
.font(.title3)
.padding()
.background(Color.green)
}
}
.navigationTitle(String(describing: Self.self))
}
}
struct View2: View
{
#Binding var view1ToView2NavBinding: Bool
var body: some View
{
HStack
{
Button {
view1ToView2NavBinding = false
} label: {
Text("Go Back")
.font(.title3)
.padding()
.background(Color.yellow)
}
}
.navigationTitle(String(describing: Self.self))
}
}
As per my concept, View1 has a property view1ToView2Navigation, which is passed to isActive param of NavigationLink. And this property is passed as binding to View2. When I set it false in View2, everything above View1 should dismiss. But this is not working, Am I missing out something conceptually ??
My RootView is enclosed in a NavigationView. And When I do the same between Root and View1. It works smoothly.
Edited: Based on your new comment, you want to navigate back to root from view 2.
Try the below code. When you press the yellow back button in view2, you will be navigated back to root.
import SwiftUI
struct ContentView: View
{
#Environment(\.dismiss) var dismissValue: DismissAction
#State var toRoot = false
var body: some View
{
NavigationView
{
HStack {
Button {
dismissValue()
} label: {
Text("Go Back")
.font(.title3)
.padding()
.background(Color.yellow)
}
NavigationLink {
View1(toRoot: $toRoot)
} label: {
Text("Go Forward")
.font(.title3)
.padding()
.background(Color.green)
}
}
}
.navigationTitle(String(describing: Self.self))
}
}
struct View1: View
{
#Environment(\.dismiss) var dismissValue: DismissAction
#Binding var toRoot: Bool
var body: some View
{
HStack
{
Button {
dismissValue()
} label: {
Text("Go Back")
.font(.title3)
.padding()
.background(Color.yellow)
}
NavigationLink {
View2(toRoot: $toRoot)
} label: {
Text("Go Forward")
.font(.title3)
.padding()
.background(Color.green)
}
}
.navigationTitle(String(describing: Self.self))
.onAppear {
if toRoot {
dismissValue()
}
}
}
}
struct View2: View
{
#Binding var toRoot: Bool
#Environment(\.dismiss) var dismissValue: DismissAction
var body: some View
{
HStack
{
Button {
toRoot = true
dismissValue()
} label: {
Text("Go Back")
.font(.title3)
.padding()
.background(Color.yellow)
}
}
.navigationTitle(String(describing: Self.self))
}
}

How can I go to a view by clicking on a Button in SwiftUI

If the user clicks on connexionBtnView I want to redirect them to an AdminView or UserView
import SwiftUI
struct ConnexionView: View {
#State var loginId: String = ""
#State var pwd: String = ""
#StateObject private var keyboardHander = KeyBoardHandler()
var body: some View {
NavigationView{
ZStack{
Image("background")
.ignoresSafeArea()
VStack (spacing: 15){
Spacer()
logoView
Spacer()
titleView
loginIdView
loginPwdView
connexionBtnView
Spacer()
NavigationLink {
LostPwdView()
} label: {
lostPwd
}
Spacer()
}.frame(maxHeight: .infinity)
.padding(.bottom,keyboardHander.keyboardHeight)
.animation(.default)
}
}
}
The NavigationLink has the isActive parameter. You can pass it in the init of NavigationLink and when this state variable has the true value you will redirect to another view. Details here.
struct ConnexionView: View {
#State var isActive: Bool = false
var body: some View {
NavigationView {
VStack {
NavigationLink(isActive: $isActive) {
LostPwdView()
} label: {
Text("Some Label")
}
Button("Tap me!") {
isActive = true
}
}
}
}
}
struct LostPwdView: View {
var body: some View {
Text("Hello")
}
}
What you need to do is having a #State variable that would trigger the navigation:
.fullScreenCover(
isPresented: $viewShown
) {
print("View dismissed")
} content: {
NextView()
}
Where NextView() is the View you want to show and the viewShown is your State variable, below a full example:
struct ExampleView: View {
#State var isNextPageOpen = false
var body: some View {
Button("Tap Here To Navigate") {
isNextPageOpen = true
}
.fullScreenCover(
isPresented: $isNextPageOpen
) {
print("View dismissed")
} content: {
NextView()
}
}
}

SwiftUI How to push to next screen when tapping on Button

I can navigate to next screen by using NavigationButton (push) or present with PresentationButton (present) but i want to push when i tap on Buttton()
Button(action: {
// move to next screen
}) {
Text("See More")
}
is there a way to do it?
You can do using NavigationLink
Note: Please try in real device. in simulator sometimes not work properly.
struct MasterView: View {
#State var selection: Int? = nil
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailsView(), tag: 1, selection: $selection) {
Button("Press me") {
self.selection = 1
}
}
}
}
}
}
struct DetailsView: View {
#Environment(\.presentationMode) var presentation
var body: some View {
Group {
Button("Go Back") {
self.presentation.wrappedValue.dismiss()
}
}
}
}
As you can see to display the new view, add the NavigationLink with isActive: $pushView using <.hidden()> to hide the navigation "arrow".
Next add Text("See More") with tapGesture to make the text respond to taps. The variable pushView will change (false => true) when you click "See More" text.
import SwiftUI
struct ContentView: View {
#State var pushView = false
var body: some View {
NavigationView {
List {
HStack{
Text("test")
Spacer()
NavigationLink(destination: NewView(), isActive: $pushView) {
Text("")
}.hidden()
.navigationBarTitle(self.pushView ? "New view" : "default view")
Text("See More")
.padding(.trailing)
.foregroundColor(Color.blue)
.onTapGesture {
self.pushView.toggle()
}
}
}
}
}
}
struct NewView: View {
var body: some View {
Text("New View")
}
}
ContentView picture
NewView picture
To tap on button and navigate to next screen,You can use NavigationLink like below
NavigationView{
NavigationLink(destination: SecondView()) {
Text("Login")
.padding(.all, 5)
.frame(minWidth: 0, maxWidth: .infinity,maxHeight: 45, alignment: .center)
.foregroundColor(Color.white)
}
}
You can use NavigationLink to implement this:
struct DetailsView: View {
var body: some View {
VStack {
Text("Hello world")
}
}
}
struct ContentView: View {
#State var selection: Int? = nil
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailsView(), tag: 1, selection: $selection) {
Button("Press me") {
self.selection = 1
}
}
}
}
}
}

Resources