Reputation: 3857
I've got a simple chat view that scrolls up to reveal new messages that appear at the bottom of the chat. What's weird is that sometimes, the duration of the scroll animation is much longer than normal.
I think it happens when a message comes in while the animation is still underway.
My code looks like this:
struct
OverlayChatView: View
{
@ObservedObject public var stream : ChatStream
var body: some View {
ScrollViewReader { scrollView in
ScrollView {
LazyVStack(alignment: .leading, spacing: 0.0) {
ForEach(self.stream.messages) { inMsg in
ChatMessageCell(message: inMsg)
}
.onChange(of: self.stream.messages, perform: { inMessages in
if inMessages.count < 1 { return }
withAnimation(.linear(duration: 0.25)) {
scrollView.scrollTo(inMessages.last!.id, anchor: .bottom)
}
})
.padding(8)
}
}
}
}
}
self.stream
is passed in from an @ObservedObject
ChatStream
with a simple Timer inserting a new message every 5.0 seconds. If the interval is 2.0 seconds, then it just continually scrolls upward slowly.
One other thing I notice is that .onChange()
gets called three times for each insert. Perhaps my ChatStream
is doing something dumb. I mention it because just invoking the animation three times in quick succession doesn't cause the slowdown. It seems more related to where the scroll is currently vs where it has to go.
Any idea how I can avoid this slowdown?
Upvotes: 6
Views: 2195
Reputation: 31
I ran into this bug when testing my app for iOS 14 (the issue seems to have been fixed in iOS 15).
The solution I found is to just wrap the withAnimation call within a main thread async call, like so:
DispatchQueue.main.async {
withAnimation(.linear(duration: 0.25)) {
scrollView.scrollTo(inMessages.last!.id, anchor: .bottom)
}
}
Upvotes: 3