SwiftUI SF Symbols Button in NavigationBar not working - swift

I'm trying to use a button that is a SF Symbol Image as the trailing navigation bar item, however, when clicking the button on a REAL IPHONE, it's very very unreliable and I end up clicking it 30+ to only get 1 click registered.
My code looks like this:
NavigationView {
List {
Text("Example")
} .navigationBarTitle("Tasks").navigationBarItems(trailing:
Button(action: { print("I was clicked!")}) {
Image(systemName: "plus")
}
)
}
However, when I put the same button outside of navigationBarItems, the button registers clicks much easier.
What can I do here?
Is this a problem with SwiftUI, if so, is there a workaround?
Thanks!

You can add padding to the image to increase the hitbox of the image
Image(systemName: "plus")
.padding([.leading, .top, .bottom])

Related

MacOS Toolbar Space makes Items disappear despite sufficient space

I created a macOS App with a NavigationView and a Toolbar.
Somehow next to my toolbarItem there is a lot of space.. So whenever I change the size of my apps window the toolbarItem disappears. Despite there is still a lot of space for my item.
I did not find out how to reduce that space..
Can you help me?
var body: some View {
NavigationView {
}
.toolbar(content: {
ToolbarItem(placement: .navigation) {
Image(systemName: "gearshape")
.frame(height: 20)
}
})
I found the problem.
The title is existing and just invisible.
You can remove the title by adding .windowToolbarStyle(.unifiedCompact(showsTitle: false))
to the WindowGroup.

SwiftUI Button cannot be clicked on its whole area

I built a custom Button.
My problem is, that it can be only clicked on the Text Elements not on the whole area of the Button.
What's going wrong, how can I solve this?
struct MyButton: View {
var body: some View
{ Button( action:{ print("pressed") })
{ HStack {
VStack(alignment: .leading){
Text("Tomorrow").font(.caption)
Text("23.5.22 KW 23")
}
Spacer()
}
}
.padding([.horizontal],4.0)
.padding([.vertical],2.0)
.background(RoundedRectangle(cornerRadius: 5).fill(Color.red))
.buttonStyle(PlainButtonStyle())
.padding([.horizontal],8.0)
}
}
By default, only the parts of the view that actually render something are tappable. You need to add a .contentShape(Rectangle()) modifier to your Button to make the entire area interactive.

How come my NavigationLink won't work when clicked?

I am trying to make it so that when I click the icon, the "scoreView()" is opened. When I click it, nothing works right now. Here is the code:
HStack {
Image(systemName: "arrow.counterclockwise")
NavigationLink(destination: scoreView(scoreTracker: $scoreTracker)) {
Spacer()
Image(systemName: "list.bullet")
}
}
Does it have something to do with the fact that I don't have a navigationView? I'm new to this and experimenting so I'm not very clear on it.
EDIT:
I have added a NavigationView, yet the NavigationLink covers half the screen, and when clicked, the view is only changed in that square.
Before clicking the NavigationLink
After clicking the NavigationLink
HStack {
Image(systemName: "arrow.counterclockwise")
NavigationView {
NavigationLink(destination: scoreView(scoreTracker: $scoreTracker)) {
Image(systemName: "list.bullet")
}
}
}
Does it have something to do with the fact that I don't have a navigationView?
Yes. According to the documentation:
Users click or tap a navigation link to present a view inside a NavigationView.
It will only work inside a NavigationView. If you're not using one, consider sheet or fullScreenCover instead. Or, make your own overlay with a ZStack.
Example NavigationView usage:
struct ContentView: View {
var body: some View {
NavigationView { /// directly inside `var body: some View`
VStack { /// if you have multiple views, make sure to put them in a `VStack` or similar
Text("Some text")
/// `ScoreView` should be capitalized
NavigationLink(destination: ScoreView(scoreTracker: $scoreTracker)) {
Image(systemName: "list.bullet")
}
}
}
}
}

Accessibility of Image in Button in ToolbarItem

I am adding accessibility into my SwiftUI app, until I encountered a problem when adding an accessibilityLabel(_:) to a Button in a ToolbarItem. Here is some sample code:
struct ContentView: View {
var body: some View {
NavigationView {
Text("Content")
.accessibilityElement()
.accessibilityLabel("Content label") // This is here just to show Voice Control is working
.navigationTitle("Test")
.toolbar {
// Comment parts out below, depending on what you want to test
ToolbarItem(placement: .navigationBarTrailing) {
// What I want, but doesn't work:
// (Also tried adding the label to either the button
// label or the whole button itself, neither works.)
Button {
print("Pressed")
} label: {
Image(systemName: "plus")
.accessibilityElement()
.accessibilityLabel("Some label")
}
.accessibilityElement()
.accessibilityLabel("Some other label")
// What I don't want, but does work:
Image(systemName: "plus")
.accessibilityLabel("Another label")
}
}
}
}
}
I am testing the accessibility with Voice Control. What is strange is that the accessibility label works for the image in the toolbar item, but not when inside a button in the toolbar item.
When I say the accessibility label doesn't work, it says "Add" instead of the expected label. I assume SwiftUI creates this label by default for the system image "plus", but I would like to change it.
The button accessibility labels also work when not in a toolbar item. Is this a bug, or some issue I have caused?
SwiftUI treats single toolbar items differently (applies their own style, size etc). It looks like this applies to accessibility labels as well.
Fortunately, there is a workaround - see SwiftUI Xcode 12.3 can't change button size in toolbar.
In your case, the code should look like:
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
HStack {
Text("")
.accessibilityHidden(true)
Button {
print("Pressed")
} label: {
Image(systemName: "plus")
.accessibilityElement()
.accessibilityLabel("Some label")
}
}
}
}
(accessibilityLabel can be attached either to the Image or to the Button.)
Tested with Xcode 12.3, iOS 14.3.
Update: this has been fixed for iOS 15+.
My radar had 'Less than 10' similar reports, but is now actually fixed for iOS 15+. However, if you are supporting older versions, see the answer above by #pawello2222 and here is an updated version to only do the workaround if necessary:
/// Embeds the content in a view which removes some
/// default styling in toolbars, so accessibility works.
/// - Returns: Embedded content.
#ViewBuilder func embedToolbarContent() -> some View {
if #available(iOS 15, *) {
self
} else {
HStack(spacing: 0) {
Text("")
.frame(width: 0, height: 0)
.accessibilityHidden(true)
self
}
}
}

tvOS Button inside NavigationLink is not Working

I have built an iOS app using swift and swiftui and now I am working on the tvOS version of the app. However, I have a couple of issues. One of the issues is still unresolved: tvOS Textfield Transparent Background
I was creating a login page and I realized that the button inside the NavigationLink was not doing anything. Then to test and identify the issue I created a simple button as follows:
Button(action: {
print("Login pressed")
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
Output when clicked on:
Login pressed
And it looks like this:
And it looks like this when focused:
But when I insert that button inside a NavigationLink, Navigation like acts like a button and this button does nothing.
The code is like that:
NavigationLink(destination: mainScene(), tag:1, selection: $selection) {
Button(action: {
print("Login pressed")
self.selection = 1
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
}
In the iOS, I have a similar code, and it does not navigate until everything in the button action is executed and selection is equal to 1. But in this, it does not execute anything and it just directly navigates to the next page. The button looks like this when I embed it in the NavigationLink:
As you can see there is white space around the original login button and the focus is on that white space. And when clicked on it navigates. It looks like the NavigationLink acts like a button but it also prevents the button action to be executed. I am having these kind of problems that are mainly caused by the focus. For Example in the images above, as you can see the shape and the color of the button changes when the focus is on but I want to control it. However, I don't know how I can play with on focus design of the items.
Try the following
Button(action: {
print("Login pressed")
self.selection = 1
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
.background(NavigationLink(destination: mainScene(), tag:1,
selection: $selection) { EmptyView() })
Try This:
NavigationLink(destination: mainScene(), tag:1, selection: $selection) {
Button(action: {
print("Login pressed")
self.selection = 1
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
}.buttonStyle(PlainButtonStyle())