MacOS Toolbar Space makes Items disappear despite sufficient space - swift

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.

Related

The EditButton for NavigationView is not working properly for iPad ( But correct for iPhone)

I am new in SwiftUI developing, In a SwiftUI project, I created a list of items then I followed the tips in this link to enabled edit button for this,
https://developer.apple.com/documentation/swiftui/editbutton
It works properly for iPhone interface, But in iPad, It has a very strange behaviour. Look at this video below to see how it works in iPad.
https://imgur.com/a/0CLkqiz
If you check this, the way it shows in iPad, when the Edit button text wants to turn to Done, the text steps forward and also creates a transparency with done and edit while it works properly and smooth and fixed in iPhone. I wonder if there might be any special settings for iPad interface in SwiftUI that would fix this problem.
This is my code for this:
struct QRCreator: View {
#State var showingCreateView = false
#State public var fruits = [
"Apple",
"Banana",
"Papaya",
"Mango"
]
var body: some View {
NavigationView {
List {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
}
.onDelete { fruits.remove(atOffsets: $0) }
.onMove { fruits.move(fromOffsets: $0, toOffset: $1) }
}
.navigationTitle("Fruits2")
.navigationBarItems(trailing:
Button(action: {
showingCreateView = true
}){
Image(systemName: "plus.viewfinder")
.font(.largeTitle)
}
)
.toolbar {
EditButton()
}
}
}
and here is ContentView which I define three tabs in it like this
TabView
{
NavigationView{
QRScanner()
}
.tabItem
{
Image(systemName: "qrcode.viewfinder")
Text("Scanner")
}
NavigationView {
QRCreator()
}
.tabItem
{
Image(systemName: "doc.fill.badge.plus")
Text("Creator")
}
NavigationView
{
QRSetting()
}
.tabItem
{
Image(systemName: "gear")
Text("Setting")
}
}
There seem to be two layers at play:
From the screen recording, it would appear that your NavigationView is actually wrapped by another NavigationView (or NavigationStack/SplitView) somewhere further up the view hierarchy in your implementation. Besides the odd layout, this also creates a tricky situation in regards to toolbar items like your buttons, and the EditMode environment value that EditButton manipulates.
There is an iPad-specific animation bug in SwiftUI's implementation of EditButton. When clicked with a mouse/trackpad as in your screen recording, the button briefly shows both labels ("Edit" & "Done") at the same time. This doesn't happen when you tap the button directly.
It is only when issues 1 & 2 collide, that I actually run into the more problematic behavior that you've captured: the button jumps and the list also jumps.
If I keep everything as you have shown it (including the doubled-up NavigationViews), but tap the button instead of clicking it with a cursor, things seem fine (although I would expect other possible issues down the road).
If I get rid of the outer NavigationView, but click the button, the button itself still exhibits a slightly odd animation, but it is nowhere near as bad as before. And most importantly, the list animates and behaves correctly.
I tried a couple of approaches to work around the button's remaining animation bug, but nothing short of re-implementing a custom edit button worked.
PS: I know you might've already come across this, but since you said that you're just starting out with iOS 16 introduced new views and APIs for navigation (and in typical fashion for SwiftUI's documentation, older pages like the one for EditButton have not been updated). Depending on how complex your app is, switching later on can be a bit of a pain, so here's a good WWDC video introducing the new API: The SwiftUI cookbook for navigation as well as some blog posts.

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

How to disable vertical scroll in TabView with SwiftUI?

I have set up a TabView in my application, so that I can swipe horizontally between multiple pages, but I also have an unwanted vertical scroll that may appear, with a bounce effect so. How can I disable this vertical scroll?
My code:
struct ContentView: View {
#State private var currentTabIndex: Double = 0
var body: some View {
VStack {
TabView(selection: $currentTabIndex) {
Text("Text n°1")
.tag(0)
Text("Text n°2")
.tag(1)
}
.border(Color.black)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}
I had this same problem. It's not an exact solution, but you can turn off bouncing on scrollviews (which is used within a TabView). And as long as the items within the TabView are not larger than the TabView frame, it should act as if you disabled vertical scrolling.
I would call it either .onAppear or in your init function:
.onAppear(perform: {
UIScrollView.appearance().bounces = false
})
Note: this disables the bouncing on ALL scrollviews across your app... So you may want to re-enable it .onDisappear.
Still an issue with Xcode 12.4.
I managed to workaround that by wrapping the TabView within a ScrollView and using the alwaysBounceVertical property set to false, as follow:
ScrollView(.horizontal) {
TabView {
///your content goes here
}
.tabViewStyle(PageTabViewStyle())
}
.onAppear(perform: {
UIScrollView.appearance().alwaysBounceVertical = false
})
.onDisappear(perform: {
UIScrollView.appearance().alwaysBounceVertical = true
})
I actually came across this because I saw this effect in a tutorial but couldn’t replicate it on iOS 15.2. However, I managed to replicate it on iOS 14.4 on another simulator side by side. So I guess this behaviour is disabled or fundamentally changed in the newer iOS.
Demonstration

SwiftUI SF Symbols Button in NavigationBar not working

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

How can I vertically center text-only TabBar buttons in SwiftUI?

I'm making some TabView buttons in SwiftUI (Xcode 11.1, Swift 5.1, and iOS 13.1.3).
For my TabView, I don't want any images -- just text. This code accomplishes that nicely:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
Text("The First Tab")
.tabItem {
Text("My Projects")
}
Text("Another Tab")
.tabItem {
Text("Augmented Reality")
}
Text("The Last Tab")
.tabItem {
Text("Products")
}
}
}
}
However, in this case, the text ends up aligned to the very bottom of the tab bar items, like this:
What I want, though is for the tab bar not to reserve space for the icons, and to vertically center the text -- something like this mock-up:
I've tried sticking it in a VStack and trying to adjust the alignment, but nothing changes.
Is there some smart way to do this, or do I need to do some sort of offset by a specific number of points?
Also FYI, Apple's developer doc says, "Tab views only support tab items of type Text, Image, or an image followed by text. Passing any other type of view results in a visible but empty tab item."
I should add that I can use .offset to adjust the entire TabView, but that's obviously not what we want. .tabItem itself ignores any .offset given, as does the Text within .tabItem.
I was able to get closer, by doing this -- essentially I'm moving the content view for each tab down by 40.0 points, and then moving the entire TabView up by 40. This looks much closer, but the background behind the tabs is then messed up:
Here's the code:
struct ContentView: View {
let vOffset: CGFloat = 40.0
var body: some View {
TabView {
Text("The First Tab")
.tabItem {
Text("My Projects")
}.offset(CGSize(width: 0.0, height: vOffset))
Text("Another Tab")
.tabItem {
Text("Augmented Reality")
}.offset(CGSize(width: 0.0, height: vOffset))
Text("The Last Tab")
.tabItem {
Text("Products")
}.offset(CGSize(width: 0.0, height: vOffset))
}
.offset(CGSize(width: 0.0, height: -vOffset))
}
}
Here's what it looks like:
I assume it will be possible in some way to fix that background, though haven't quite figured out how yet.
The other thought is that I wonder if it's even a good idea to do this sort of "hacky" thing. Or if this even is a hacky thing? I know the whole idea of the declarative nature of SwiftUI is to separate the implementation from the declaration. With that in mind, it would be conceivable to expect that some future implementation could look very different, and thus be made to look stupid via the hacky offsets I'm doing here.
That aside, I still want to do it, for now anyway. 😊
So for now I'm looking for a way to fix the background color of the tab bar area, and also, of course, a less hacky way to solve the original problem.
Thanks!
Update: Xcode 13.3 / iOS 15.4
Not Text is entered (that can be considered as fix for PO)...
... but image is always shown to the top of center (independently of there is text or not):
The empty space is room for an icon. The TabView is not really customizable. You can turn the text into graphics and insert it using Image - that should push it upwards. It won’t be perfectly centered though.
try
TabView(alignment: .center ,spacing: 20))
{
Text("The First Tab")
.tabItem {
Text("My Projects")
}
}