Button grayed out in toolbar initially - swift

I have a SwiftUI macOS application, and I noticed that when you have a button in a toolbar, its image is initially grayed out until you hover over or click it.
I am using macOS Montery Beta 3, and Xcode 13 Beta 3.
Simple Reproduction
Create a new SwiftUI macOS project
Paste the following code:
struct ContentView: View {
var body: some View {
NavigationView {
Text("Panel1").padding()
.toolbar {
Button(action: {}) {
Image(systemName: "plus")
}
}
Text("Panel2").padding()
}
}
}
Run the application, and you should see that the plus button is grayed out. However hovering over or clicking it makes the button not gray.
This question is very similar to this, but instead with a toolbar.
Whats happening here?

I had the same issue and discovered that you need to specify the color explicitly.
.toolbar {
Button(action: {}) {
Image(systemName: "plus")
}
Button(action: {}) {
Image(systemName: "plus")
.foregroundColor(.white)
}
}

Related

how to change the size of the iPad pointer highlight on a toolbar button

I’ve set up a basic sample project that has a toolbar with an sf symbol button. I would like to change the size of the highlight that is shown when the button is selected with an iPad cursor. I tried changing the frame, which works with a normal button, but not when one is in the toolbar. here is my code:
NavigationView {
VStack {
Text("Hello World!")
}.toolbar {
ToolbarItem{
Button(action: {}) {
Image(systemName: "square.and.arrow.up")
}
.frame(width: 20, height: 20)
.padding(0)
}
}
}

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

Creating a navbar with 3 items

I'm trying to create something like this:
A navigation bar with 3 items, is it possible to do this using navigationBarItems?
My current plan is to hide the navbar using:
.navigationBarTitle("")
.navigationBarHidden(true)
and then creating the 3 buttons using a HStack. The Problem I have is because I'm hiding the navbar, the click of one of the buttons take it to another view, which also then hides the navbar (Thats not what im looking for)
I have tried:
.navigationBarItems(trailing:
HStack {
Button("About") {
print("About tapped!")
}
Button("Help") {
print("Help tapped!")
}
}
)
But this creates the two items next to each other on the right side. I tried putting a Spacer() in the above HStack, but this doesn't work.
I would prefer to use navigationBarItems but can't seem to find a way to centre an item?
A navigation bar with 3 items, is it possible to do this using navigationBarItems?
No. Moreover navigationBarItems modifier is deprecated since SwiftUI 2.0
SwiftUI 2.0
This can be done with toolbar modifier as easy as attach it to any view inside NavigationView
Demo prepared & tested with Xcode 12 / iOS 14:
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {}) { Image(systemName: "gear") }
}
ToolbarItem(placement: .principal) {
Button(action: {}) { Image(systemName: "car") }
}
ToolbarItem(placement: .navigation) {
Button(action: {}) { Image(systemName: "chevron.left") }
}

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