Menu on NavigationLink is not tapable - swiftui

How can I put a Menu on a NavigationLink destination? This approach opens only the destination and never the menu when I tap on it.
var body: some View {
NavigationView {
NavigationLink (
destination: Text("Hello")
label: {
ZStack(alignment: .topTrailing){
Rectangle()
.frame(width: 300, height: 100)
Menu {
Button("Order Now", action: {print("1")})
Button("Adjust Order", action: {print("2")})
} label: {
Label("Options", systemImage: "paperplane")
}
}
})
.buttonStyle(PlainButtonStyle())
}
}
EDIT: Just to clarify: The Menu is in the top right corner. When I tap on this menu button, the menu should appear. Otherwise when I tap on the rest of the view the destination of the NavigationLink should be opened

Okay.. third time's a charm.. so they say!
I made it harder than what it needed to be but that is a working example of Menu and I learned from this myself
import SwiftUI
struct navViewTest: View {
var body: some View {
NavigationView {
VStack {
Text("Hello World")
}.navigationBarItems(trailing:
Menu {
Button("Option 1", action: {doSomething() })
Button("Option 2", action: {doSomething() })
} label: {Text("Menu") }
)
}
}
private func doSomething() { }
}
struct navViewTest_Previews: PreviewProvider {
static var previews: some View {
navViewTest()
}
}

I've found a "solution". A little bit hacky, but it works so far. I just wrapped the menu in a button:
Button(action: {/*do something*/}, label: {
Menu {
Button("Option 1", action: {print("1") })
Button("Option 2", action: {print("2") })
} label: {Text("Menu") }
})

Related

Closing A View From Another View

I am still learning SwiftUI and I have come across a small problem.
In my app, I have a main view. On the top is a search bar and at the bottom, a menu with different buttons. I want to change views when clicking those buttons. However, I only want to change the middle section.
No big deal, I will just put the middle part into a NavigationView. That works alright and I am able to change my views. My problem is that the buttons below do not have any impact on the new view.
To try to simplify: Let’s say I’m on home page. I then click the grocery list button (guess what I’m making school projects lol). My navigation link works just fine and goes to the list. So, now I’m on view 2 let’s say. When I press the home button, it doesn’t close that view and go to my main one. Here is my code setup:
import SwiftUI
struct ContentView: View {
#State private var searchText: String = ""
#State private var action: Int? = 0
var body: some View {
ZStack {
// Top Menu
VStack{
HStack {
Spacer()
TextField("Search",
text: $searchText)
.background(Color.white)
Button(action: {
self.action = 1
}, label: {
Image(systemName: "magnifyingglass.circle")
.font(.largeTitle)
})
Spacer()
}
// Body
NavigationView {
VStack {
Text("Can I See Something")
NavigationLink(destination: SearchView(), tag: 1, selection: $action) {
}
Text("Yes/No")
}
}
Spacer()
// Bottom Menu
HStack (alignment: .top) {
Spacer()
VStack {
Button(action: {
}, label: {
Image(systemName: "house.fill")
.font(.largeTitle)
})
.padding(.top)
Text("Home")
}
Divider()
.padding(.horizontal)
.frame(width: 2.5, height: 100)
VStack {
Button(action: {
}, label: {
Image(systemName: "newspaper")
.font(.largeTitle)
})
.padding(.top)
Text("Weekly\nAd")
.multilineTextAlignment(.center)
}
Divider()
.padding(.horizontal)
.frame(width: 2.5, height: 100)
VStack {
Button(action: {
}, label: {
Image(systemName: "checklist")
.font(.largeTitle)
})
.padding(.top)
Text("Grocery\nList")
.multilineTextAlignment(.center)
}
Divider()
.padding(.horizontal)
.frame(width: 2.5, height: 100)
VStack {
Button(action: {
}, label: {
Image(systemName: "person.crop.circle")
.font(.largeTitle)
})
.padding(.top)
Text("Account")
}
Spacer()
}
}
}
}
}
struct SearchView: View {
var body: some View {
ZStack {
Text("Nothing to see here!")
}
.navigationBarBackButtonHidden(true)
}
}
SearchView is a separate view (in its own file) in the app that opens up when the magnifying glass button is pressed. Currently it does not do anything. However I want to be able to press those buttons on this view above to still navigate the app.
Also, on another note, is there anyway to get rid of the back button?
In your code the buttons do not have any function.
Instead of creating a tab bar on your own, I'd rather take something like:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
MainView()
.tabItem {
Label("Home", systemImage: "house.fill")
}
NewsView()
.tabItem {
Label("Weekly\nAd", systemImage: "newspaper")
}
OrderView()
.tabItem {
Label("Grocery\nList", systemImage: "checklist")
}
AccountView()
.tabItem {
Label("Account", systemImage: "person.crop.circle")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct MainView: View {
var body: some View {
Text("Home View")
}
}
struct NewsView: View {
var body: some View {
Text("News View")
}
}
struct OrderView: View {
var body: some View {
Text("Order View")
}
}
struct AccountView: View {
var body: some View {
Text("Account View")
}
}
In that case you'll have to create a view for each tab you are configuring (see the last 4 structs).
If you want to do it with a Stack with your own created buttons, I think you should create al 4 views as well and then you either hide them or put them out of focus by using an offset. In that case the buttons should hide/show the specific views or change the offset accordingly to move the specific views into the visible area. With the offset you also can add some animation.
Regarding the search bar on top of your app, since the views are all different, I wouldn't keep the same search bar everywhere, but if you really want to have it that way, you can embed the code + your search bar into a VStack (as you did it in your example).

onTapGesture To Dismiss Keyboard Makes View Inoperable

I am working on a SwiftUI app. In the app I have a custom coded List that acts as a Form. The reason it is custom coded is because I am using a custom color. I have TextField rows among other rows that act as Navigation Links. My issue is that when I add a onTapGesture to dismiss the keyboard all other row functions stop working. For example the NavigationLinks.
NavigationLink Work Here
ZStack(alignment: .leading, content: {
Color.pacificBlue
.edgesIgnoringSafeArea(.all)
List {
Section(header: Text("Header") {
NavigationLink(
destination: SecondaryView(),
label: {
Text("Secondary View")
})
TextField("MyField", text: self.$myField)
}
}
}
NavigationLink Does Not Work Here
ZStack(alignment: .leading, content: {
Color.pacificBlue
.edgesIgnoringSafeArea(.all)
List {
Section(header: Text("Header") {
NavigationLink(
destination: SecondaryView(),
label: {
Text("Secondary View")
})
TextField("MyField", text: self.$myField)
}
}
}
.onTapGesture {
self.dismissKeyboard()
}
Dismiss Keyboard
extension View {
func dismissKeyboard() {
let resign = #selector(UIResponder.resignFirstResponder)
UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil)
}
}
Is there a way to work around this without having to move to a secondary view to add text. Any help would be appreciated.
Taking the answer from: SwiftUI NavigationLink in list
the following works for me for NavigationLink. If you have
a Button for example, this will not work.
struct ContentView: View {
#State var myField = ""
#State private var showIt: Int? = 0 // <-- here
var body: some View {
NavigationView {
ZStack(alignment: .leading) {
Color.blue.edgesIgnoringSafeArea(.all)
List {
Section(header: Text("Header")) {
// -- here --
NavigationLink(destination: Text("destination view"), tag: 1, selection: $showIt) {
Text("Secondary View")
}.disabled(true) // <-- here
.onTapGesture { showIt = 1 } // <-- here
TextField("MyField", text: $myField)
}
}.listStyle(.plain)
}
.onTapGesture {
self.dismissKeyboard()
}
}.navigationViewStyle(.stack)
}
}

How can I present Menu (Not context menu) by using a Button in SwiftUI?

struct MainMenuView: View {
var body: some View {
Menu("Actions") {
Button("Duplicate", action: duplicate)
Button("Rename", action: rename)
Button("Delete…", action: delete)
}
}
}
Button(action:{
MainMenuView()
}, label: { Text("More") })
I have a "Menu" view it's just a menu, and I want to present it in another view using button action closure, so when tapping the button the menu pops up, anyone can help me with this, please.
Try this Using toolbar as an example
.toolbar{
ToolbarItem(placement: .primaryAction) {
Menu {
Button(action: {//action}) {
Label("Bttn 1", systemImage: "text.badge.plus")
}
Button(action: {//action}) {
Label("Bttn 2", systemImage: "text.badge.plus")
}
}
label: {
Label("Add", systemImage: "plus")
.font(.title2)
.foregroundColor(.white)
}
}
}

SwiftUI - Form Picker & Button Not Co-Existing

I have created a reusable component that has a picker, textfield and button within a form. However, with the button present, a tap on the picker field does not go to the picker. Rather it executes the button code. The TextField works fine. If I remove the button code, the proper behavior will occur with the picker. So the question is how to have both elements within this component? Please note that the preview adds the Navigation and Form which would otherwise come from the parent view.
var body: some View {
HStack {
if !showFee {
Spacer()
Button(action: {
withAnimation(.easeInOut(duration: 0.3)) {
self.showFee.toggle()
}
}) {
Image(systemName: "plus.circle")
.font(.largeTitle)
}
Spacer()
} else {
VStack(spacing:20) {
Picker(selection: $feeSelection, label: Text("Fee Type")) {
ForEach(0 ..< fees.count) {
Text(self.fees[$0])
}
}
TextField("Fee Amount: $", value: $feeAmount, formatter: NumberFormatter.currency)
.keyboardType(.decimalPad)
Divider()
Button(action: {
withAnimation(.easeInOut(duration: 0.3)) {
self.showFee.toggle()
}
}) {
Image(systemName: "trash.circle.fill")
.font(.largeTitle)
.foregroundColor(.red)
}
}
}
}
.padding()
}
}
struct FeeCell_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
Form {
FeeCell()
}
}
}
}
What you can do is to apply the PlainButtonStyle to your button. This will stop the button's tap covering to the whole cell in the Form:
Button(action: {}) {
Text("Button")
}
.buttonStyle(PlainButtonStyle())

SwiftUI Navigation Issues, 'Group' not resolving

Environment: Xcode 11.1 running on Catalina (19A573a) and building iOS only app.
I have the following code that should be fairly simple.
- I have buttons A - H (8 buttons)
- When I tap on a button I expect to be taken to a respective view (“View A”, “View B”, etc) as they are embedded in a NavigationView.
I run into several issues
- With the code shown tapping button for “View A” does nothing but the other buttons work.
- After re-running a few times tapping on button A will work some times but fail most of the time
- If I disable displaying of all the buttons except button A tapping on button A works.
- If I disable displaying of any single button (again there are 8 buttons, A-H) then tapping on the first button works.
I understand there is a technical limit in VStack of more than 10 view and I tried the suggestion made here:
https://www.hackingwithswift.com/quick-start/swiftui/how-to-group-views-together
But that does not work
I have tried variations of putting the buttons in the list and that doesn’t work.
Anyone who wants to test can create a new project and copy the entire code contents into the ContentView.swift file and run.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
HStack {
Spacer()
VStack {
Spacer()
Group {
NavigationLink(destination: ViewA()) {
BasicButton(buttonName: "View A", buttonColor: .orange)
}
NavigationLink(destination: ViewB()) {
BasicButton(buttonName: "View B", buttonColor: .red)
}
NavigationLink(destination: ViewC()) {
BasicButton(buttonName: "View C", buttonColor: .green)
}
NavigationLink(destination: ViewD()) {
BasicButton(buttonName: "View D", buttonColor: .blue)
}
}
Group {
NavigationLink(destination: ViewE()) {
BasicButton(buttonName: "View E", buttonColor: .pink)
}
NavigationLink(destination: ViewF()) {
BasicButton(buttonName: "View F", buttonColor: .gray)
}
NavigationLink(destination: ViewG()) {
BasicButton(buttonName: "View G", buttonColor: .purple)
}
NavigationLink(destination: ViewH()) {
BasicButton(buttonName: "View H", buttonColor: .yellow)
}
}
Spacer()
}
Spacer()
}
.background(Color.black).edgesIgnoringSafeArea(.all)
}
}
}
struct BasicButton: View {
var buttonName: String
var buttonColor: Color
var body: some View {
Text(buttonName)
.font(.title)
.multilineTextAlignment(.center)
.foregroundColor(.white)
.frame(width: 300, height: 60)
.background(buttonColor)
.cornerRadius(5)
.padding()
}
}
struct ViewA: View {
var body: some View {
Text("View A").font(.largeTitle)
}
}
struct ViewB: View {
var body: some View {
Text("View B").font(.largeTitle)
}
}
struct ViewC: View {
var body: some View {
Text("View C").font(.largeTitle)
}
}
struct ViewD: View {
var body: some View {
Text("View D").font(.largeTitle)
}
}
struct ViewE: View {
var body: some View {
Text("View E").font(.largeTitle)
}
}
struct ViewF: View {
var body: some View {
Text("View F").font(.largeTitle)
}
}
struct ViewG: View {
var body: some View {
Text("View G").font(.largeTitle)
}
}
struct ViewH: View {
var body: some View {
Text("View H").font(.largeTitle)
}
}
When you open Debug View Hierarchy you will notice that View A is completely obstructed by a invisible NavigationBar, which even though it is invisible is blocking all the touches from reaching View A.