SwiftUI equivalent of popoverTouchBar and pressAndHoldTouchBar - swiftui

SwiftUI Touch Bar support seems quite limited.
Is there an equivalent of popoverTouchBar and pressAndHoldTouchBar?
I tried doing a popover as follows:
.touchBar {
Button(action: { self.showRadiusTouchBarSlider.toggle() }) {
Text("Radius")
}.popover(isPresented: self.$showRadiusTouchBarSlider) {
Slider(value: self.$model.radius, in: Float(0.0)...Float(1.0))
}
}
Amusingly, that puts a touch-bar styled slider in the corner of the screen:

Related

SwiftUI ScrollView horizontal scroll lag on macOS

Faced with a very strange ScrollView behavior on macOS. The content freezes under the mouse during horizontal scrolling. But it is worth taking the mouse away from the window and the content scrolls normally.
This happens when I try to use a vertical scroll inside a horizontal one:
struct ScrollTestView: View {
var body: some View {
ScrollView(.horizontal) {
ScrollView(.vertical) {
VStack {
ForEach(0..<20, id: \.self) { row in
HStack {
ForEach(0..<20, id: \.self) { item in
Text("\(item)")
.font(.title)
.padding()
.background {
Color.gray
}
}
}
}
}
}
}
}
}
Yes, I know that I can use the same ScrollView for both axes simultaneously, but I need solution with two ScrollViews because of desired UX.
This solution is perfectly works on iOS, but I have this strange behavior on macOS.
Also if you swap a horizontal and a vertical ScrollView in the exact same code, everything works just fine:
struct ScrollTestView: View {
var body: some View {
ScrollView(.vertical) {
ScrollView(.horizontal) {
// ...
}
}
}
}
Looks like this is a SwiftUI bug, but I am not sure, maybe I am missing something?
Any ideas?

Title for Keyboard Shortcut in SwiftUI

I want to change the discoverability title of a keyboard shortcut in SwiftUI.
As you can see below the title shows in the popup if used in text button, but if you use an image for the button it doesn't show in the popup (when holding cmd on the keyboard to view supported shortcuts by the app).
struct ContentView: View {
var body: some View {
VStack {
Button("Save to Favorites") {
}
.keyboardShortcut("a")
Button {
} label: {
Image(systemName: "heart.fill")
}
.keyboardShortcut("s")
}
}
}
How can I add a title to the shortcuts help popup?
Note that I have tried all accessibility stuff, i.e. label, identifier, hint, etc... and It didn't work.
Not a super elegant solution but I got it working by adding a Text with a .frame size of width: 0, height: 0. This effectively hides the Text from view but ensures it appears when the user holds down the ⌘ key.
Consider putting it in a ZStack too as the default arrangement could have it ever so slightly off centre.
VStack {
Button("Save to Favorites") {
}
.keyboardShortcut("a")
Button {
} label: {
ZStack {
Text("heart")
.frame(width: 0, height: 0) // <- this part
Image(systemName: "heart.fill")
}
}
.keyboardShortcut("s")
}

How do I get a ToolbarItem with primaryAction placement to display under the navigation bar on WatchOS in SwiftUI

I am trying to figure out how to hide the primaryAction ToolbarItem under the navigation bar in a watchOS app written in SwiftUI. Apple's documentation states
In watchOS the system places the primary action beneath the navigation bar; the user reveals the action by scrolling.
ToolbaritemPlacement - primaryAction
Here is the view that I am using:
var body: some View {
NavigationView {
ScrollView {
VStack(alignment: .leading) {
ForEach(0..<100) {
Text("Row \($0)")
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Settings") {}
}
}
}
}
.navigationTitle("Navigation")
}
The primary action button always displays and is never hidden. I have seen an example where one used a ScrollViewReader to programmatically change the position but I feel like that isn't what Apple has stated is possible and I'm trying to understand what I'm doing wrong. Apple's documentation also states that the toolbar needs to be inside the scrollview:
Place a toolbar button only in a scrolling view. People frequently scroll to the top of a scrolling view, so discovering a toolbar button is almost automatic. Placing a toolbar button in a nonscrolling view makes it permanently visible, eliminating the advantage of hiding it when it’s not needed.
Toolbar Buttons watchOS
Try this:
struct ContentView: View {
var body: some View {
ScrollView {
VStack(alignment: .leading) {
ForEach(0..<100) {
Text("Row \($0)")
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Settings") {}
}
}
.navigationTitle {
Text("Navigation")
}
}
}
}

SwiftUI 2.0 ToolbarItem Labels showing sideways

Trying to figure out how to put the icons of the new SwiftUI toolbar on top of the text, like they are supposed to be on the bottom toolbar. Currently, they show up sideways, which is weird.
This is my piece of code that shows them
content.toolbar {
ToolbarItem(placement: .bottomBar) {
Button {
menu.value = .file
} label: {
Label(LocalizedStringKey("menu.file"),
systemImage: Symbol.SymbolEnum.sf_folder.systemName! )
}
}
ToolbarItem(placement: .bottomBar) {
Button {
menu.value = .export
} label: {
Label(LocalizedStringKey("menu.export"),
systemImage: Symbol.SymbolEnum.sf_square_and_arrow_up.systemName! )
}
}
}
I know it is simple to do a VStack, but I seriously thought this was the entire goal of a Label, to be able to provide something contextually adequate, and in this case, it would be a vertical orientation for the icon and text.
There is LabelStyle for this purpose, so we could configure labels as needed.
So here is possible approach
struct VerticalLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
VStack(spacing: 0) {
configuration.title
configuration.icon
}
}
}
and now apply it to entire toolbar or to needed labels only
Label(LocalizedStringKey("menu.file"),
systemImage: Symbol.SymbolEnum.sf_folder.systemName! )
.labelStyle(VerticalLabelStyle())

SwiftUI navigationBarItem showing in strange position after showing a different bigger item

I have a simple split view that looks roughly like this:
NavigationView {
VStack {
Button(action: {
self.selectedView = 1
}) {
Text("First")
}
Button(action: {
self.selectedView = 2
}) {
Text("Second")
}
}
Group {
if selectedView == 1 {
Text("View")
.navigationBarItems(trailing: Text("Hi"))
} else {
Text("View")
.navigationBarItems(trailing: Rectangle().frame(width: 150))
}
}
}
Now the navigation bar item Hi initially shows in the correct position (very far left). However, when I switched to the second view, which presents a really long rectangle in the navigation bar, and switch back to the original view, the Hi text is now shown in where the middle of the rectangle used to be (see picture).
Any idea why this is happening?