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

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())

Related

SwiftUI extra space at top of list above section header. On testing device only

I have been trying to figure out what is causing the space at the top of the screen in my production app, so I made this test app to see if it is a bug or not. The code works as intended on a simulator but when a testing device runs the code it adds extra space. The space goes away after you start scrolling, and does not comeback until the view reloads. I have tried restarting the device and other devices. I took out .navigationTitle and .navigationBarTitleDisplayMode and it did not fix the problem. So far my best guess is that there is some problem with changing the section header in .onAppear(). Changing it to .task() seems to be a workaround for now.
struct DetailView: View {
#State var item: Item
#State private var headerText = "Header"
var body: some View {
List {
Section(header: Text("\(headerText)")) {
Text("Text")
}
HStack {
Text("Red Text")
}.listRowBackground(Color.red)
// Change to .task instead
}.onAppear {
headerText = "Change Header"
}
}
}
Edit: Here is the code for the list view, it is the default new project setup.
var body: some View {
NavigationView {
List {
ForEach(items) { item in
NavigationLink(destination: DetailView(item: item), label: {
Text(item.timestamp!, formatter: itemFormatter)
})
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
Text("Select an item")
}
}
In my case this behaviour was caused by .navigationViewStyle(StackNavigationViewStyle()).
Looks like it's a bug with NavigationView in SwiftUI 4 since it wasn't like this before.
If you are on iOS 16 use NavigationStack instead NavigationView. This fixed all my problems and I didn't even need to use the navigationViewStyle anymore.
NavigationView is deprecated in favor of NavigationStack.

Jumpy toolbar items in NavigationView

I tried to use a custom view as the navigation title inside a NavigationView. Every time when the detail view is popped up, the toolbar items are always resized quickly in a second. I also tested adding a button there as ToolbarItem, the same. Am I misuing something?
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink {
Text("Detail")
.toolbar {
VStack {
Text("title")
Text("subtitle")
}
}
} label: {
Text("Detail")
}
}
}
}
You're missing Toolbar item inside .toolbar.
.toolbar {
ToolbarItem(placement: .principal) { //You're missing this.
VStack {
Text("title")
Text("subtitle")
}
}
}

Why the ToolbarItem Button is not tappable?

I have a navigationView with the ToolbarItem containing a button.
This button is not tappable correctly. To move to the next screen i have to tap underneath.
As you can see from the Debug View Hierarchy:
Here is how i am adding the button to the toolbar:
var body: some View {
ZStack { ... }
.navigationBarTitle(Text("Format"), displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Next") {
setCanvas()
}
}
}
}
This view is being pushed with a NavigationLink
The solution is to add an .id to the Button in order to force the Button to render it self. I was showing a modal before this and it had that position.
var body: some View {
ZStack { ... }
.navigationBarTitle(Text("Format"), displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Next") {
setCanvas()
}
.id(UUID())
}
}
}

Rename Cancel button on a modal sheet

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")
}
}
}
}
}
}

Can't not click NavigationLink in Form(SwiftUI)

struct SettingView: View {
var body: some View {
NavigationView {
Form {
Section(header: Text("我的")) {
NavigationLink(destination: PlanListView()) {
HStack {
Text("我的计划")
}
}
}
}
.navigationBarTitle("Setting")
.navigationBarItems(trailing:
Button(action: {
}) {
Image(systemName: "bell.circle.fill")
.font(Font.system(.title))
}
)
}
}
}
I want to use Form with Section to Build my list, and I also want some row click to navigate to another view, but it not working with my code.
update full code, I can work this code in Xcode12 SwiftUI Preview, but not work in simulator and ture device
finally, test, I have a TabView with SettingView(), Single SettingView can open NavigationLink but in TabView can not work