Presenting a sheet pops views from NavigationView - ios

I have a view A that contains a NavigationView. A pushes View B by activating a NavigationLink. B pushes View C by activating a NavigationLink. C pushes View D by tapping a NavigationLink. D then presents a View as a sheet. If i dismiss the sheet the current top view is B. For some reason presenting the sheet pops 2 screens.
Can someone explain this behaviour and how i can fix it?
I'm guessing somehow the navigation link in view B (that pushed view C) get deActivated but I cant figure out why
From what i tested it seems when the sheet gets presented ViewB gets reinitialized which will reinit my vm and so deactivate the link. How to i stop the view from being reinitialized?
struct ViewA: View {
#SwiftUI.Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
#ObservedObject private var viewModel: ViewAVM
var body: some View {
NavigationView {
GeometryReader { fullView in
ScrollView(.vertical, showsIndicators: false) {
if !self.viewModel.loading {
VStack(alignment: .leading, spacing: 0) {
DetailsView(car: self.$viewModel.data)
Spacer(minLength: 20)
NavigationLink(destination: ViewB(rootActive: self.$viewModel.showB), isActive: self.$viewModel.showB) {
Button(action: {
self.viewModel.showB = true
}) {
SecondaryButtonView(enabled: true, title: "Go")
}
}.isDetailLink(false).padding([.leading, .trailing], 20)
}.frame(minHeight: fullView.size.height)
}
}
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle("View A")
.navigationBarItems(leading: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Image("LeftArrow").renderingMode(.original)
})
.onAppear {
self.viewModel.update()
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
struct ViewBUI: View {
#SwiftUI.Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
#ObservedObject private var viewModel: ViewBVM
private let rootActive: Binding<Bool>
var body: some View {
GeometryReader { fullView in
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading, spacing: 0) {
Text("").font(.regularParagraph).padding(.top, 15).padding(.bottom, 10)
CustomEntryView()
Spacer(minLength: 20)
NavigationLink(destination: ViewC(rootActive: self.rootActive), isActive: self.$viewModel.showC) {
Button(action: {
self.hideKeyboard()
self.viewModel.validate()
}) {
PrimaryButtonView(enabled: self.viewModel.valid, title: "Continue")
}.disabled(!self.viewModel.valid)
}.isDetailLink(false).padding(.bottom, 16)
}.padding([.leading, .trailing], 20).frame(minHeight: fullView.size.height)
}
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle(viewModel.new ? "New" : "Old")
.navigationBarItems(leading: Button(action: {
self.viewModel.rootActive.wrappedValue = false
}) {
Image("LeftArrow").renderingMode(.original)
})
}
}
struct ViewDUI: View {
#SwiftUI.Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
let isDriver: Bool
let car: Binding<Car?>
let rootActive: Binding<Bool>
var body: some View {
GeometryReader { fullView in
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading, spacing: 0) {
Text("").font(.regularParagraph).foregroundColor(Color.black).padding([.leading, .trailing], 20).padding(.top, 15)
CarDetailsView(car: self.car)
Spacer(minLength: 20)
if self.car.wrappedValue?.mot == true && self.car.wrappedValue?.taxed == true {
if self.isDriver {
Button(action: {
self.rootActive.wrappedValue = false
}) {
PrimaryButtonView(enabled: true, title: "Save")
}.padding(.bottom, 16).padding([.leading, .trailing], 20)
} else {
NavigationLink(destination: ViewE(rootActive: self.$viewModel.showB)) {
PrimaryButtonView(enabled: true, title: "Continue")
}.isDetailLink(false).padding(.bottom, 16).padding([.leading, .trailing], 20)
}
} else {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
PrimaryButtonView(enabled: true, title: "")
}.padding(.bottom, 16).padding([.leading, .trailing], 20)
}
}.frame(minHeight: fullView.size.height)
}
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle("")
.navigationBarItems(leading: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Image("LeftArrow").renderingMode(.original)
})
}
}
struct ViewEUI: View {
#SwiftUI.Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
private let rootActive: Binding<Bool>
private let isDriver: Bool
#State private var showingScanner = false
#State private var scanHandler: LicenseScanHandler!
#State private var scanCompleted = false
var body: some View {
VStack(alignment: .leading, spacing: 0) {
Text("")
.font(.regularParagraph)
.padding(.top, 15)
.padding([.leading, .trailing], 20)
ZStack(alignment: .topLeading) {
VStack(alignment: .leading, spacing: 0) {
Image("sample")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(20)
}
.overlay(RoundedRectangle(cornerRadius: 3).stroke(Color.azure, lineWidth: 1))
.background(Color.white.edgesIgnoringSafeArea(.all))
.padding(.top, 12)
Text("")
.font(.tinyParagraph)
.foregroundColor(.azure)
.frame(width: 80, height: 24)
.background(Color.white.edgesIgnoringSafeArea(.all))
.cornerRadius(8)
.overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.azure, lineWidth: 1))
.padding(.leading, 20)
}
.padding([.leading, .trailing], 40)
.padding(.top, 16)
Spacer(minLength: 20)
Button(action: {
self.showingScanner = true
}) {
PrimaryButtonView(enabled: true, title: "Scan")
}.padding(.bottom, 16).padding([.leading, .trailing], 20)
.sheet(isPresented: $showingScanner) {
ScannerWrapper(handler: self.scanHandler)
}
NavigationLink(destination: InfoUI(), isActive: $scanCompleted) {
Text("")
}.isDetailLink(false)
}
.background(Color.offWhite.edgesIgnoringSafeArea(.all))
.navigationBarBackButtonHidden(true)
.navigationBarTitle("")
.navigationBarItems(leading: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Image("LeftArrow").renderingMode(.original)
})
.onAppear {
self.scanHandler = LicenseScanHandler(delegate: self)
}
}
}

Although it is not documented, I realised that presenting a .sheet() while the view itself is set to a "no detail view" via .isDetailLink(false) causes this issue.
I can see why, as if the view is not a detail view it cannot present a sheet, hence the sheet is actually presented by the first detail view and that is why it goes back to that view right after the sheet is presented.
Try removing .isDetailLink(false) and finding a different workaround if you really need it to be not a detail link.

Related

SwiftUI - ExpandableView inside VStack

I'm trying to have multiple expandable views with animation inside a VStack. I have the following code:
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
VStack {
ExpandableView(headerTitle: "First")
ExpandableView(headerTitle: "Second")
Spacer()
}
}
}
}
}
And the ExpandableView:
struct ExpandableView: View {
let headerTitle: String
#State private var collapsed: Bool = true
var body: some View {
Button(
action: {
self.collapsed.toggle()
},
label: {
VStack(spacing: 2) {
ZStack {
Rectangle()
.fill(.gray)
VStack {
Text("\(headerTitle) Header")
if !collapsed {
HStack {
Text("Text A")
Text("Text B")
}
}
}
}
.frame(height: collapsed ? 52 : 80)
ZStack(alignment: .top) {
Rectangle()
.fill(.gray)
.frame(height: 204)
VStack {
Text("Content A")
Text("Content B")
Text("Content C")
}
}
.frame(maxHeight: collapsed ? 0 : .none)
.clipped()
}
}
)
.buttonStyle(PlainButtonStyle())
.animation(.easeOut, value: collapsed)
}
}
The result is this:
As you can see if I open the last expandableView is opens correctly. However if I open the first one when the second is closed, it actually opens the second. It only opens correctly the first one if the second is already open. It seems the VStack is not rendering correctly itself. Any ideas why this happening?
Thanks for the help.
I migth be the way the buttons works. Here is a cleaner solution:
struct ExpandableView: View {
let headerTitle: String
#State private var collapsed: Bool = true
var body: some View {
VStack(spacing: 2) {
Button(
action: {
withAnimation(.easeOut){
self.collapsed.toggle()
}
},
label: {
VStack {
Text("\(headerTitle) Header")
if !collapsed {
HStack {
Text("Text A")
Text("Text B")
}
}
}.frame(maxWidth: .infinity)
})
.buttonStyle(.borderedProminent)
.tint(.gray)
if(!self.collapsed) {
VStack {
Divider().background(.black)
Text("Content A")
Text("Content B")
Text("Content C")
}
}
Spacer()
}
.frame(height: collapsed ? 52 : 204)
.frame(maxWidth: .infinity)
.background(.gray)
.padding()
}
}

sheet inside ForEach doesn't loop over id's

Each link has an id, the output I get when I click on the button is the wrong id, it repeats the first id on the first 4 buttons and then the others are random.
struct PricesList: View {
#ObservedObject var viewModel = ViewModel()
#State var isSheetPresented = false
var body: some View{
NavigationView{
ScrollView {
LazyVGrid(columns: gridLayout, spacing: 15, content: {
ForEach(viewModel.items, id: \.id) { item in
VStack(alignment: .leading, spacing: 5){
Button(action: {
self.isSheetPresented.toggle()
}, label: {
Image(item.imageUrl)
.resizable()
.scaledToFit()
.padding(10)
}).sheet(isPresented: $isSheetPresented, content: {
WebView(url: item.link)
})
}//:VSTACK
.scaledToFit()
.padding()
.background(Color.white.cornerRadius(12))
.background(RoundedRectangle(cornerRadius: 12).stroke(Color.gray, lineWidth: 1))
}//: LOOP FOR EACH
}).padding(5)
.onAppear(perform: {
viewModel.loadData()
viewModel.postData()
})
}
.navigationBarHidden(true)
}//: NAVIGATION VIEW
} //: BODY
}
You have sheet for each item in your list, and all of them are getting isSheetPresented value. Which one will be displayed is undefined
Instead you need to store selectedItem and pass it to single sheet, like this:
struct ContentView: View {
#ObservedObject var viewModel = ViewModel()
#State var selectedItem: Item?
var body: some View{
NavigationView{
ScrollView {
LazyVGrid(columns: gridLayout, spacing: 15, content: {
ForEach(viewModel.items, id: \.id) { item in
VStack(alignment: .leading, spacing: 5){
Button(action: {
selectedItem = item
}, label: {
Image(item.imageUrl)
.resizable()
.scaledToFit()
.padding(10)
})
}//:VSTACK
.scaledToFit()
.padding()
.background(Color.white.cornerRadius(12))
.background(RoundedRectangle(cornerRadius: 12).stroke(Color.gray, lineWidth: 1))
}//: LOOP FOR EACH
}).padding(5)
.onAppear(perform: {
viewModel.loadData()
viewModel.postData()
})
.sheet(item: $selectedItem, content: { selectedItem in
WebView(url: selectedItem.link)
})
}
.navigationBarHidden(true)
}//: NAVIGATION VIEW
} //: BODY
}

I use navigationlink and I also want to use side menu

I have a NavigationView component in my iOS app that's built with SwiftUI.
I use navigationlink to change my page.In the second screen, I want to show side menu.But now I havetwo layers NavigationView in my iOS app, it's not my want to show.I want the second screen only have side menu.
is it possible or am i missing something about the way navigation is being managed in Swift?
How should I change my code?
here's my ContentView.swift:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
VStack {
NavigationLink(
destination: SwiftUIView_map(),
label: {
Text("Skip")
.fontWeight(.bold)
.font(.title)
.padding()
.background(Color.purple)
.cornerRadius(20)
.foregroundColor(.white)
})
HeaderView()
.offset(y:-60)
NavigationLink(
destination: Text("Login"),
label: {
Text("Login")
.fontWeight(.bold)
.font(.title)
.padding()
.background(Color.purple)
.cornerRadius(20)
.foregroundColor(.white)
})
NavigationLink(
destination: Text("Sign up"),
label: {
Text("Sign up")
.fontWeight(.bold)
.font(.title)
.padding()
.background(Color.purple)
.cornerRadius(20)
.foregroundColor(.white)
})
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct HeaderView: View {
var body: some View {
HStack{
VStack(alignment: .leading, spacing: 2){
Text("Just")
.font(.system(size: 60,weight:.heavy,design:.rounded))
.fontWeight(.black)
.multilineTextAlignment(.leading)
Text("test")
.font(.system(size: 60,weight:.heavy,design:.rounded))
.fontWeight(.black)
}
Spacer()
}
.padding()
}
}
The navigation sidebar:
import SwiftUI
struct SwiftUIView_map: View {
#State private var isShowing = false
var body: some View {
NavigationView{
ZStack{
if isShowing{
SideMenuView(isShowing: $isShowing)
}
HomeView()
.cornerRadius(isShowing ? 20 : 10 )
.offset(x: isShowing ? 300 : 0,y:isShowing ? 44 :0)
.scaleEffect(isShowing ? 0.8 : 1)
.navigationBarItems(leading: Button(action: {
withAnimation(.spring()){
isShowing.toggle()
}
}, label: {
Image(systemName: "list.bullet")
.foregroundColor(.black)
}))
.navigationTitle("home")
}
}
}
}
struct SwiftUIView_map_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView_map()
}
}
struct HomeView: View {
var body: some View {
ZStack{
Color(.white)
Text(/*#START_MENU_TOKEN#*/"Hello, World!"/*#END_MENU_TOKEN#*/)
.padding()
}
}
}
If you want more detailed code, please click the link
https://github.com/simpson0826/swifttest.git
You need to use the NavigationView only in ContentView(root view).
struct SwiftUIView_map: View {
#State private var isShowing = false
var body: some View {
// NavigationView{
ZStack{
if isShowing{
SideMenuView(isShowing: $isShowing)
}
HomeView()
.cornerRadius(isShowing ? 20 : 10 )
.offset(x: isShowing ? 300 : 0,y:isShowing ? 44 :0)
.scaleEffect(isShowing ? 0.8 : 1)
.navigationBarItems(trailing: Button(action: {
withAnimation(.spring()){
isShowing.toggle()
}
}, label: {
Image(systemName: "list.bullet")
.foregroundColor(.black)
}))
.navigationTitle("home")
}
// }
}
}

Reloading Previous View from Navbar

I have been following a tutorial on creating a weather app. I am trying to take it further. When on the weather view the user can click a plus button which takes them to a location view. Here the user will be able to update the location then when going back the weather will reload. But i am really struggling to get the weather to reload when pressing the back button.
Below is my code for the WeatherView & LocationView
Thank you
struct WeatherView: View {
#State private var isShowing = false
#State var width = UIScreen.main.bounds.width - 60
#State var x = -UIScreen.main.bounds.width + 60
#ObservedObject var input = CityId()
let heptics = UIImpactFeedbackGenerator(style: .medium)
#ObservedObject var weatherViewModel = WeatherViewModel()
var body: some View {
NavigationView{
ZStack {
BackgroundView()
VStack {
if weatherViewModel.stateView == .loading {
ActivityIndicatorView(isAnimating: true).configure {
$0.color = .white
}
}
if weatherViewModel.stateView == .success {
LocationAndTemperatureHeaderView(data: weatherViewModel.currentWeather)
Spacer()
ScrollView(.vertical, showsIndicators: false) {
VStack {
DailyWeatherCellView(data: weatherViewModel.todayWeather)
Rectangle().frame(height: CGFloat(1))
HourlyWeatherView(data: weatherViewModel.hourlyWeathers)
Rectangle().frame(height: CGFloat(1))
DailyWeatherView(data: weatherViewModel.dailyWeathers)
Rectangle().frame(height: CGFloat(1))
Text(weatherViewModel.currentDescription)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(
.init(arrayLiteral:.leading,.trailing),
24
)
Rectangle().frame(height: CGFloat(1))
DetailsCurrentWeatherView(data: weatherViewModel.currentWeather)
Rectangle().frame(height: CGFloat(1))
}
}
Spacer()
}
if weatherViewModel.stateView == .failed {
Button(action: {
self.weatherViewModel.retry()
}) {
Text("Failed get data, retry?")
.foregroundColor(.white)
}
}
}
}.colorScheme(.dark)
.listStyle(InsetGroupedListStyle())
.background(
NavigationLink(destination: LocationView(input: input, weatherViewModel: weatherViewModel), isActive: $isShowing) {
EmptyView()
}
) // End of Background
.navigationBarTitle((input.score), displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing){
Button(action: {
isShowing = true
heptics.impactOccurred()
}) {
Image(systemName: "plus")
}
} // End of ToolbarItem
} // End of Toolbar
} // End of Nav View
} // End of body
} // End of View
struct LocationView: View {
#ObservedObject var input: CityId
#ObservedObject var weatherViewModel: WeatherViewModel
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Button(action: {
input.score = "2643743"
weatherViewModel.stateView = .loading
self.presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "plus")
}
.navigationBarBackButtonHidden(true)
}
}
You may consider adding .onAppear modifier to your first view then you can update the data.

NavigationView and NavigationLink on button click in SwiftUI?

I am trying to push from login view to detail view but not able to make it.even navigation bar is not showing in login view. How to push on button click in SwiftUI? How to use NavigationLink on button click?
var body: some View {
NavigationView {
VStack(alignment: .leading) {
Text("Let's get you signed in.")
.bold()
.font(.system(size: 40))
.multilineTextAlignment(.leading)
.frame(width: 300, height: 100, alignment: .topLeading)
.padding(Edge.Set.bottom, 50)
Text("Email address:")
.font(.headline)
TextField("Email", text: $email)
.frame(height:44)
.accentColor(Color.white)
.background(Color(UIColor.darkGray))
.cornerRadius(4.0)
Text("Password:")
.font(.headline)
SecureField("Password", text: $password)
.frame(height:44)
.accentColor(Color.white)
.background(Color(UIColor.darkGray))
.cornerRadius(4.0)
Button(action: {
print("login tapped")
}) {
HStack {
Spacer()
Text("Login").foregroundColor(Color.white).bold()
Spacer()
}
}
.accentColor(Color.black)
.padding()
.background(Color(UIColor.darkGray))
.cornerRadius(4.0)
.padding(Edge.Set.vertical, 20)
}
.padding(.horizontal,30)
}
.navigationBarTitle(Text("Login"))
}
To fix your issue you need to bind and manage tag with NavigationLink, So create one state inside you view as follow, just add above body.
#State var selection: Int? = nil
Then update your button code as follow to add NavigationLink
NavigationLink(destination: Text("Test"), tag: 1, selection: $selection) {
Button(action: {
print("login tapped")
self.selection = 1
}) {
HStack {
Spacer()
Text("Login").foregroundColor(Color.white).bold()
Spacer()
}
}
.accentColor(Color.black)
.padding()
.background(Color(UIColor.darkGray))
.cornerRadius(4.0)
.padding(Edge.Set.vertical, 20)
}
Meaning is, when selection and NavigationLink tag value will match then navigation will be occurs.
I hope this will help you.
iOS 16+
Note: Below is a simplified example of how to present a new view. For a more advanced generic example please see this answer.
In iOS 16 we can access the NavigationStack and NavigationPath.
Usage #1
A new view is activated by a simple NavigationLink:
struct ContentView: View {
var body: some View {
NavigationStack {
NavigationLink(value: "NewView") {
Text("Show NewView")
}
.navigationDestination(for: String.self) { view in
if view == "NewView" {
Text("This is NewView")
}
}
}
}
}
Usage #2
A new view is activated by a standard Button:
struct ContentView: View {
#State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
Button {
path.append("NewView")
} label: {
Text("Show NewView")
}
.navigationDestination(for: String.self) { view in
if view == "NewView" {
Text("This is NewView")
}
}
}
}
}
Usage #3
A new view is activated programmatically:
struct ContentView: View {
#State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
Text("Content View")
.navigationDestination(for: String.self) { view in
if view == "NewView" {
Text("This is NewView")
}
}
}
.onAppear {
path.append("NewView")
}
}
}
iOS 13+
The accepted answer uses NavigationLink(destination:tag:selection:) which is correct.
However, for a simple view with just one NavigationLink you can use a simpler variant: NavigationLink(destination:isActive:)
Usage #1
NavigationLink is activated by a standard Button:
struct ContentView: View {
#State var isLinkActive = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
...
NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {
Button(action: {
self.isLinkActive = true
}) {
Text("Login")
}
}
}
.navigationBarTitle(Text("Login"))
}
}
}
Usage #2
NavigationLink is hidden and activated by a standard Button:
struct ContentView: View {
#State var isLinkActive = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
...
Button(action: {
self.isLinkActive = true
}) {
Text("Login")
}
}
.navigationBarTitle(Text("Login"))
.background(
NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {
EmptyView()
}
.hidden()
)
}
}
}
Usage #3
NavigationLink is hidden and activated programmatically:
struct ContentView: View {
#State var isLinkActive = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
...
}
.navigationBarTitle(Text("Login"))
.background(
NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {
EmptyView()
}
.hidden()
)
}
.onAppear {
self.isLinkActive = true
}
}
}
Here is a GitHub repository with different SwiftUI extensions that makes navigation easier.
Another approach:
SceneDelegate
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: BaseView().environmentObject(ViewRouter()))
self.window = window
window.makeKeyAndVisible()
}
BaseView
import SwiftUI
struct BaseView : View {
#EnvironmentObject var viewRouter: ViewRouter
var body: some View {
VStack {
if viewRouter.currentPage == "view1" {
FirstView()
} else if viewRouter.currentPage == "view2" {
SecondView()
.transition(.scale)
}
}
}
}
#if DEBUG
struct MotherView_Previews : PreviewProvider {
static var previews: some View {
BaseView().environmentObject(ViewRouter())
}
}
#endif
ViewRouter
import Foundation
import Combine
import SwiftUI
class ViewRouter: ObservableObject {
let objectWillChange = PassthroughSubject<ViewRouter,Never>()
var currentPage: String = "view1" {
didSet {
withAnimation() {
objectWillChange.send(self)
}
}
}
}
FirstView
import SwiftUI
struct FirstView : View {
#EnvironmentObject var viewRouter: ViewRouter
var body: some View {
VStack {
Button(action: {self.viewRouter.currentPage = "view2"}) {
NextButtonContent()
}
}
}
}
#if DEBUG
struct FirstView_Previews : PreviewProvider {
static var previews: some View {
FirstView().environmentObject(ViewRouter())
}
}
#endif
struct NextButtonContent : View {
var body: some View {
return Text("Next")
.foregroundColor(.white)
.frame(width: 200, height: 50)
.background(Color.blue)
.cornerRadius(15)
.padding(.top, 50)
}
}
SecondView
import SwiftUI
struct SecondView : View {
#EnvironmentObject var viewRouter: ViewRouter
var body: some View {
VStack {
Spacer(minLength: 50.0)
Button(action: {self.viewRouter.currentPage = "view1"}) {
BackButtonContent()
}
}
}
}
#if DEBUG
struct SecondView_Previews : PreviewProvider {
static var previews: some View {
SecondView().environmentObject(ViewRouter())
}
}
#endif
struct BackButtonContent : View {
var body: some View {
return Text("Back")
.foregroundColor(.white)
.frame(width: 200, height: 50)
.background(Color.blue)
.cornerRadius(15)
.padding(.top, 50)
}
}
Hope this helps!
Simplest and most effective solution is :
NavigationLink(destination:ScoresTableView()) {
Text("Scores")
}.navigationBarHidden(true)
.frame(width: 90, height: 45, alignment: .center)
.foregroundColor(.white)
.background(LinearGradient(gradient: Gradient(colors: [Color.red, Color.blue]), startPoint: .leading, endPoint: .trailing))
.cornerRadius(10)
.contentShape(Rectangle())
.padding(EdgeInsets(top: 16, leading: UIScreen.main.bounds.size.width - 110 , bottom: 16, trailing: 20))
ScoresTableView is the destination view.
In my opinion a cleaner way for iOS 16+ is using a state bool to present the view.
struct ButtonNavigationView: View {
#State private var isShowingSecondView : Bool = false
var body: some View {
NavigationStack {
VStack{
Button(action:{isShowingSecondView = true} ){
Text("Show second view")
}
}.navigationDestination(isPresented: $isShowingSecondView) {
Text("SecondView")
}
}
}
}
I think above answers are nice, but simpler way should be:
NavigationLink {
TargetView()
} label: {
Text("Click to go")
}

Resources