How to align navigationTitle with menu button (toolbarItem)? - swiftui

I have a navigationView with a toolbarItem button to block/report users. But the navigationTitle is not aligned with the menu button...
is there a way to align them horizontally?
otherwise I'll be forced to ditch the toolbar and just use a HStack as header.
NavigationView{
VStack {
...bunch of code
}
.navigationBarTitle(Text(model.matches[index].name).font(.subheadline), displayMode: .large)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Menu(content: {
Text("Menu Item 1")
Text("Menu Item 2")
Text("Menu Item 3")
}, label: {Image(systemName: "ellipsis")})
}
}
//.ignoresSafeArea(.top)
}

.navigationBarTitle(Text(model.matches[index].name).font(.subheadline), displayMode: .inline)

Related

SwiftUI: Hidden NavigationBar blocks UI

I am using a NavigationView to navigate between views. As I don't want to use the NavigationBar, I am hiding it. Unfortunately, the area where the NavigationBar was (it is hidden) is still blocking the UI. A button there cannot be tapped.
How can I fix this?
// First View
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Spacer()
Text("Title")
Spacer()
NavigationLink(destination: View2()) {
Text("Next")
}
.navigationBarTitle("", displayMode: .inline)
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
Spacer()
}
}
}
}
and
// Second View: Here the button cannot be tapped
struct View2: View {
var body: some View {
NavigationView {
VStack {
Button(action: {
print("this button doesn't work")
}, label: {
Text("Do something")
})
Spacer()
}
.padding(.top, 50)
.edgesIgnoringSafeArea(.all)
}
.navigationBarTitle("", displayMode: .inline)
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
}
}
The issue is due to used second NavigationView - it is wrong, there should be only one root navigation view which manages navigation stack in this case.
So here is fixed view (child one)
struct View2: View {
var body: some View {
VStack {
Button(action: {
print("this button doesn't work")
}, label: {
Text("Do something")
})
Spacer()
}
.padding(.top, 50)
.edgesIgnoringSafeArea(.all)
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
}
}
Tested with Xcode 13.2 / iOS 15.2
Note: as you hide navigation but you don't need mode modifier as well, so removed .navigationBarTitle("", displayMode: .inline). Just for your info.

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

SwiftUI: How to set foregroundColor on menu button

I would like to make a menu button red as it carries a destructive nature, but my implementation doesn't override the foreground color at all.
Code.
ToolbarItem(placement: .navigationBarTrailing) {
Menu {
Button(action: {}) {
Label("Delete", systemImage: "trash")
.foregroundColor(.red)
}
}
label: {
Text("Next")
}
}
Other attempts:
ToolbarItem(placement: .navigationBarTrailing) {
Menu {
Button(action: {}) {
Label("Delete", systemImage: "trash")
}
.foregroundColor(.red)
}
label: {
Text("Next")
}
}
Results
Noticed that the "Delete" button is not red.

SwiftUI: Menu inside list cell with onTapGesture triggers gesture

I have a SwiftUI List on iOS14.3 (Xcode12.3) and inside it's cells I want to have a Menu popup up when the user is tapping on a button. Additionally these cells have an onTapGesture and the problem is that this gesture is also triggered when the menu button is pressed.
Example:
List {
HStack {
Text("Cell content")
Spacer()
// Triggers also onTapGesture of cell
Menu(content: {
Button(action: { }) {
Text("Menu Item 1")
Image(systemName: "command")
}
Button(action: { }) {
Text("Menu Item 2")
Image(systemName: "option")
}
Button(action: { }) {
Text("Menu Item 3")
Image(systemName: "shift")
}
}) {
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
}
}
.background(Color(.systemBackground))
.onTapGesture {
print("Cell tapped")
}
}
If you tap on the ellipsis image, the menu opens but also "Cell tapped" will be printed to the console. This is a problem for me, because in my real world example I am collapsing the cell within the tap gesture and of course I don't want that to happen when the user presses the menu button.
I found out, that when I long press on the button the gesture won't be triggered. But this is not acceptable UX in my opinion, took me a while to find that out for my self.
I also noticed, when I replace the Menu with a regular Button, then the cells gesture is not triggered while pressing (only with BorderlessButtonStyle or PlainButtonStyle, otherwise he is not active at all). But I don't know how to open a Menu from it's action.
List {
HStack {
Text("Cell content")
Spacer()
// Does not trigger cells onTapGesture, but how to open Menu from action?
Button(action: { print("Button tapped") }) {
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
}
.buttonStyle(BorderlessButtonStyle())
}
.background(Color(.systemBackground))
.onTapGesture {
print("Cell tapped")
}
}
Alternatively, you can override Menu onTapGesture:
struct ContentView: View {
var body: some View {
List {
HStack {
Text("Cell content")
Spacer()
Menu(content: {
Button(action: {}) {
Text("Menu Item 1")
Image(systemName: "command")
}
Button(action: {}) {
Text("Menu Item 2")
Image(systemName: "option")
}
Button(action: {}) {
Text("Menu Item 3")
Image(systemName: "shift")
}
}) {
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
}
.onTapGesture {} // override here
}
.contentShape(Rectangle())
.onTapGesture {
print("Cell tapped")
}
}
}
}
Also, there's no need to use .background(Color(.systemBackground)) to tap on spacers. This is not really flexible - what if you want change background color?
You can use contentShape instead:
.contentShape(Rectangle())
I'm not sure if this is a bug or expected behavior, but instead of fighting with it I would recommend to avoid such overlapping (because even with success today it might stop working on different systems/updates).
Here is possible solution (tested with Xcode 12.1 / iOS 14.1)
List {
HStack {
// row content area
HStack {
Text("Cell content")
Spacer()
}
.background(Color(.systemBackground)) // for tap on spacer area
.onTapGesture {
print("Cell tapped")
}
// menu area
Menu(content: {
Button(action: { }) {
Text("Menu Item 1")
Image(systemName: "command")
}
Button(action: { }) {
Text("Menu Item 2")
Image(systemName: "option")
}
Button(action: { }) {
Text("Menu Item 3")
Image(systemName: "shift")
}
}) {
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
}
}
}

TabBar Change Selected Tab Icon Background Color swiftui

I have this TabBArViewController which has 5 tabs in it.
struct TabBarViewController: View {
#State private var selection = 3
var body: some View {
ZStack {
TabView(selection:$selection) {
OffersView()
.tabItem ({
Image(systemName: "bag").renderingMode(.template)
Text("Offers")
})
.tag(1)
BalanceView()
.tabItem ({
Image(systemName: "creditcard").renderingMode(.template)
Text("Balance")
})
.tag(2)
StepView()
.tabItem ({
Image(systemName: "figure.walk.circle").renderingMode(.template)
Text("Steps")
})
.tag(3)
FriendsView()
.tabItem {
Image(systemName: "person.2")
Text("Friends")
}
.tag(4)
ProfileView()
.tabItem {
Image(systemName: "person")
Text("Profile")
}
.tag(5)
}
.accentColor(Color("ColorOnboarding"))
.navigationBarBackButtonHidden(true)
}
.navigationBarBackButtonHidden(true)
}
}
which appears as so
I want to add a rectangle color to this when a tab bar icon selected in SwiftUI. How can I do it without creating a custom tab bar?