ScrollView .scrollDismissesKeyboard(.interactively) feels weird - swiftui

I set up a ScrollView like so:
ScrollView(.vertical) {
// ...
}
.scrollDismissesKeyboard(.interactively)
.safeAreaInset(edge: .bottom, spacing: 0) {
TextInputCellView(with: Color(hex: 0xf5f9fc)) { value in
vm.send(text: value)
}
}
The newly added scrollDissmissesKeyboard works, does however look and feel a little weird. Is this a bug or am i doing anything wrong ?

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?

Why are those NavigationLinks not clickable?

I have this code:
ScrollView () {
VStack(spacing: 0) {
ForEach(0..<10) {position in
NavigationLink(destination: DestinationView(position)) {
TimetableCellView(position)
}.padding(.all, 0.0)
}.padding(.all, 0.0)
}.cornerRadius(30.0).padding(.all)
}
It looks and feels as it should (besides the greyed out look of the TimetableCellViews in the list), but I can't click on the links. Any ideas how to solve?
Thx.

SwiftUI scroll to horizontal list item

I'm able to scroll to a vertical List item using ScrollViewReader proxy.
I tried doing something similar with Horizontal list, but it totally messed up the view.
Any suggestion, how this can be done ?
tia!
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators:false) {
ForEach(0..<items.count) { index in
Text(items[index].title)
.id(index)
.onTapGesture {
print("tapped \(index)")
}
}
.onAppear{
proxy.scrollTo(selectedIndex, anchor: .center)
}
}
}
ScrollView will not layout your views in a row just because you've specified .horizontal scrolling.
You need to specify HStack/LazyHStack explicitly inside ScrollView.
Another problem you may have encountered is that the scrolling position is not accurate, this can be fixed with DispatchQueue.main.async:
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack { // or LazyHStack
ForEach(0..<items.count) { index in
Text(items[index].title)
.id(index)
.onTapGesture {
print("tapped \(index)")
}
}
}
.onAppear {
DispatchQueue.main.async {
proxy.scrollTo(selectedIndex, anchor: .center)
}
}
}
}

SwiftUI: animating scroll on ScrollView programmatically?

I need to programmatically animate the scroll of a scrollview. The scrollview contains either an HStack or a VStack. Code I tested with is this:
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: spacing) {
ForEach(cids, id: \.self) { cid in
....
}
}
.onAppear {
withAnimation(Animation.easeInOut(duration: 4).delay(3)) {
proxy.scrollTo(testCid)
}
}
}
.frame(maxWidth: w, maxHeight: w / 2)
}
The scrollview does land on the item with the testCid, however, it does not animate.
As soon as the view comes on screen the scrollview is already on testCid...
How can I animate the scroll?
The interactive scroll works if you start it from somewhere else (f.e. Button action) but not from the onAppear modifier. I'd guess this is intentional behavior to prevent the user seeing the scrolling when the view appears (or a bug in SwiftUI...). An ugly workaround is to defer the animation with an DispatchQueue.main.async:
import SwiftUI
struct ContentView: View {
let words = ["planet", "kidnap", "harbor", "legislation", "soap", "management", "prejudice", "an", "trunk", "divide", "critic", "area", "affair"]
#State var selectedWord: String?
var body: some View {
ScrollViewReader { proxy in
VStack(alignment: .leading) {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(words, id: \.self) { word in
Text(word)
.background(self.selectedWord == word ? Color.yellow : nil)
.id(word)
}
}
}
Button("Scroll to random word") {
withAnimation(Animation.easeInOut(duration: 1)) {
let word = words.randomElement()
self.selectedWord = word
proxy.scrollTo(word)
}
}
}
.onAppear {
DispatchQueue.main.async { // <--- workaround
withAnimation(Animation.easeInOut(duration: 1).delay(1)) {
let word = self.words.last
self.selectedWord = word
proxy.scrollTo(word)
}
}
}
}
.padding(10)
}
}

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?