Rename Cancel button on a modal sheet - swiftui

I currently invoke an Example Sentence modal sheet by toggling $showingModal on a certain condition.
.sheet(isPresented: $showingModal) {
ExampleSentence()
}
According to the Human Interface Guidelines, I am able to rename Cancel to something more appropriate such as Dismiss. If I was using UIKit instead of SwiftUI, I'd be using the presentController function which then explains that I can rename the Cancel button using setTitle. https://developer.apple.com/documentation/watchkit/wkinterfacecontroller/1619560-presentcontroller
But if I'm using SwiftUI, is it possible to rename the Cancel button?
EDIT: Sorry I should have clarified that this is a watchOS app. By default it creates a Cancel button in the top left corner but I just want to rename it to dismiss.

You can do that by using a NavigationView within your ExampleSentences view and adding a toolbar to it, something like this.
struct ExampleSentence: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack {
Text("Hello View")
}
.navigationBarTitle("Example Sentences")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Done")
}
}
}
}
}
}

Related

SwiftUI - NavigationLink and NavigationStack is not working with a button for iOS 16

I am making an app where I need to navigate to the home page when the user clicks on the Login button and when the Login button is clicked, the navigation link code is not working and shows a warning as Result of 'NavigationLink<Label, Destination>' initializer is unused. FYI, please refer to the attached screenshot and the below code:
import SwiftUI
struct LoginView: View {
var nextButton: some View {
HStack {
Button("Next") {
NavigationLink {
HomeView(user: user)
} label: {
Text("Test")
}
}
.buttonStyle(PlainButtonStyle())
.font(.system(size: 24))
}
}
var body: some View {
NavigationStack {
nextButton
}
}
}
There are two problems here:
A NavigationLink is an alternative to a Button and can be used on its own for navigation. You can use a button to navigate programatically, but for this simple case a link works. Like Buttons, you can change the appearance of NavigationLinks if needed.
NavigationStack is a more powerful replacement for NavigationView. You should not mix them both. As the HomeView is your root view, the single NavigationStack for your app should be there (not in the LoginView).
struct HomeView: View {
var body: some View {
NavigationStack {
VStack {
NavigationLink {
LoginView()
} label: {
Text("Login")
}
}
}
}
}
The warning is because you are creating a NavigationLink in the button action code block, and returned NavigationLink is not assigned or used.

How to use NavigationLink inside SwiftUI sheet

I have 4 SwiftUI View:
The FirstView opens the SecondView using a sheet:
.sheet(isPresented: $showSheet) {
SecondView()
}
The SecondView opens the ThirdView using a sheet too:
.sheet(isPresented: $showSheet) {
ThirdView()
}
My expectations: I want ThirdView opens FourthView using NavigationLink (on full screen with Back button in the left corner):
NavigationLink(destination: FourthView()) {
Text("Open FourthView")
}
but I'm having trouble with the view hierarchy. If I want to use NavigationLink, somewhere I have to define NavigationView.
If I define NavigationView in the SecondView like this:
.sheet(isPresented: $showSheet) {
NavigationView {
ThirdView()
}
}
, I have sheet view with Back button, but I want a full screen view with Back button.
Could you help me with this views hierarchy, where should I put NavigationView?

Navigate to another screen in swiftUI

Below is the code i am trying to push to another swiftUI when button in swiftUI is pressed.
But it is not navigating to another screen
let controller = DestinationHostingController(rootView: AnotherSwiftUI())
pushViewController(controller, animated: animated)
In SwiftUI, the navigation has been improved,
You have to embed your view inside a NavigationView,
and after that you can use NavigationLink to redirect wherever you want
example:
struct ContentView: View {
var body: some View {
NavigationView {
VStack(spacing: 30) {
Text("You're going to flip a coin – do you want to choose heads or tails?")
NavigationLink(destination: ResultView(choice: "Heads")) {
Text("Choose Heads")
}
NavigationLink(destination: ResultView(choice: "Tails")) {
Text("Choose Tails")
}
}
.navigationTitle("Navigation")
}
}
}
(You can replace the NavigationLink content by whatever you want, Text -> Button)

How do I get a ToolbarItem with primaryAction placement to display under the navigation bar on WatchOS in SwiftUI

I am trying to figure out how to hide the primaryAction ToolbarItem under the navigation bar in a watchOS app written in SwiftUI. Apple's documentation states
In watchOS the system places the primary action beneath the navigation bar; the user reveals the action by scrolling.
ToolbaritemPlacement - primaryAction
Here is the view that I am using:
var body: some View {
NavigationView {
ScrollView {
VStack(alignment: .leading) {
ForEach(0..<100) {
Text("Row \($0)")
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Settings") {}
}
}
}
}
.navigationTitle("Navigation")
}
The primary action button always displays and is never hidden. I have seen an example where one used a ScrollViewReader to programmatically change the position but I feel like that isn't what Apple has stated is possible and I'm trying to understand what I'm doing wrong. Apple's documentation also states that the toolbar needs to be inside the scrollview:
Place a toolbar button only in a scrolling view. People frequently scroll to the top of a scrolling view, so discovering a toolbar button is almost automatic. Placing a toolbar button in a nonscrolling view makes it permanently visible, eliminating the advantage of hiding it when it’s not needed.
Toolbar Buttons watchOS
Try this:
struct ContentView: View {
var body: some View {
ScrollView {
VStack(alignment: .leading) {
ForEach(0..<100) {
Text("Row \($0)")
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Settings") {}
}
}
.navigationTitle {
Text("Navigation")
}
}
}
}

SwiftUi Navigation Bar Button disappears after entering the third View (Controller)

I have a huge Problem with SwiftUi. The "Backbutton" in a really Simple NavigationView Hierarchy disappears on the third View. If I go one view further, the Backbutton is there again and I can go back.
I searched like 3 Hours but only found this SwiftUI: Back button disappears when clicked on NavigationLink
Obviously this doesn't solve my Problem.
Thanks for any Help!
For me the issue was a bit different - the back button disappeared on the third view only after interacting with the third view, e.g. clicking into the list view.
My workaround is to use the old .navigationBarItems instead of .toolbar, so:
.navigationBarItems(trailing:
Menu {
Button(action: {
//some action
}) {
//some label
}
Button(action: {
//some action
}) {
//some label
}
}
label: {
//some label
}
)
instead of:
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Menu {
Button(action: {
//some action
}) {
//some label
}
Button(action: {
//some action
}) {
//some label
}
}
label: {
//some label
}
}
}
I found another workaround for who doesn't want to use a deprecated method.
Just add in your .toolbar this ToolBarItem:
.toolbar {
// ... other toolbar items
ToolbarItem(placement: .navigationBarLeading) {
Text("")
}
}
Another solution which seems to be working on Xcode 12.4:
ToolbarItem(placement: .navigationBarLeading) {
HStack {}
}
In case you want to make your code cleaner
/// A ToolbarItem wrapper to work around the back button disappearance bug in SwiftUI 2.
struct NavbarBackButtonDisappearanceWorkaroundItem: ToolbarContent {
var body: some ToolbarContent {
ToolbarItem(placement: .navigationBarLeading) {
Color.clear
}
}
}
Use as follows:
.toolbar {
NavbarBackButtonDisappearanceWorkaroundItem()
SomeOtherUsefulItem()
}
I found the Problem!
The .toolbar modifier on the NavigationView hides the Backbutton in a Buggy way!
I have found the solution of this problem. If you are not using .toolbar nor .navigationBarItems you should simply add .navigationBarItems(trailing: EmptyView()) to you children. This will always keep your back button alive)
var body: some View {
ScrollView() {
...
}
.navigationBarItems(trailing: EmptyView())
}
'''
you need to add to your NavigationView
.navigationViewStyle(StackNavigationViewStyle())