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

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?

Related

ScrollViewReader / scrollTo(_:anchor:) not working reliably

I've build a ScrollView which contains 0-3 images and a multiline text field in a VStack. I also added a ScrollViewReader inside the scrollview and use it to scroll to the bottom of the text field upon certain events (user starts typing, image collection changes).
The point is: sometimes it works, sometimes it doesn't. When it does not work I realized, that when I scroll a little bit by hand and then try again (e.g. typing) it works.
Not sure if this is relevant, but ImageOrPlaceholderComponent first shows a placeholder as long as the image within currentEntryImages is nil, and the image after that (both states imply a change to currentEntryImages and should thus result in scrolling to the bottom of the text field).
NavigationStack {
ScrollView {
ScrollViewReader { scrollview in
VStack {
// Attached images.
AnyLayout(VStackLayout(spacing: 2.5)) {
ForEach(values: currentEntryImages) { entryImage in
ImageOrPlaceholderComponent(image: entryImage)
.clipped()
}
}
// Text field for the entry with toolbar.
TextField("...", text: $entryDTO.text, axis: .vertical)
.id(entryTextFieldAnchor)
.multilineTextAlignment(.leading)
.padding()
.focused($mainTextFieldFocused)
.onAppear { mainTextFieldFocused = true }
// Scroll to the bottom of the text field, when the user is typing ...
.onChange(of: entryDTO.text) { _ in
withAnimation {
scrollview.scrollTo(entryTextFieldAnchor, anchor: .bottom)
}
}
// ... or the entry images have changed.
.onChange(of: currentEntryImages) { _ in
withAnimation {
scrollview.scrollTo(entryTextFieldAnchor, anchor: .bottom)
}
}
}
}
}
}

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

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 Drag events how do restrict to detect only horizontal/vertical scrolls

I have List (vertically scrolled) with nested ScrollView (or View that has dragging attached to it). I would like to have nested view onDrag() to be detected only on horizontal scrolling and not on vertical one. Vertical scrolling should be propagated to wrapper List.
Well, the following demo of horizontal scroll view inside vertical list should be working, and it is, unless List for now has known "refresh" defect. So... I decided to post it just for demo... maybe with next SwiftUI/iOS update it will be fixed automatically.
Also I provided variant of horizontal scroll view inside vertical scroll view, as a workaround to List issue. Hope any of those would be helpful.
So, demo code for "vertical drag anywhere propagated to vertical scrolling container, horizontal drag works only in horizontal scroll view"
A - Working variant of body based on vertical ScrollView (to replace in below module)
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading) {
ForEach (0..<20, id: \.self) { i in
VStack {
self.rowItem(index: i)
Divider()
}
}
}
}
}
B - "Working" variant with List (having refresh issue)
struct TestScrollInList: View {
var body: some View {
List {
ForEach (0..<20, id: \.self) { i in
self.rowItem(index: i)
}
}
}
func rowItem(index i: Int) -> AnyView {
if i % 2 == 0 {
return AnyView(self.plainItem(index: i))
} else {
return AnyView(self.scrollableItem(index: i))
}
}
func plainItem(index i: Int) -> some View {
Text("Plain item \(i)")
}
func scrollableItem(index i: Int) -> some View {
ScrollView (.horizontal, showsIndicators: false) {
HStack {
ForEach(0..<10) { j in
RoundedRectangle(cornerRadius: 8)
.fill(j % 2 == 0 ? Color.green : Color.yellow)
.frame(width: 100, height: 100)
}
}
}
.frame(maxHeight: 110)
}
}
struct TestScrollInList_Previews: PreviewProvider {
static var previews: some View {
TestScrollInList()
}
}