Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI ScrollView animated scrolling is sometimes slow

Tags:

ios

swift

swiftui

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.

Animated GIF showing sometimes-slow scrolling behavior.

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?

like image 999
Rick Avatar asked May 13 '21 22:05

Rick


People also ask

Is there a ScrollView equivalent in SwiftUI?

We will explore a ScrollView, UIScrollView equivalent in SwiftUI. List view is a view that contains child views and displays them in a scrollable manner. SwiftUI offers two views with this capability, ScrollView and List. In the previous post, we learned two ways to populate a list view's content.

How to make a scroll view scroll horizontally in jQuery?

By default, the scroll view will create with a vertical scrolling direction. To make a scroll view scroll horizontally, you passing Axis.Set.horizontal as axes argument. <1> Set axes as .horizontal to enable horizontal scrolling. <2> We use HStack instead of VStack here to align our child views horizontally.

What is the default behavior of the list view ScrollView?

The default behavior of View will simply layout them vertically, which is not scrollable. In this article, we will visit one of a list view, ScrollView. You can easily support sarunw.com by checking out this sponsor. Turn your code into a snapshot: Codeshot creates a beautiful image of your code snippets. Perfect size for Twitter. Get it now!

What is listview in SwiftUI?

List view is a view that contains child views and displays them in a scrollable manner. SwiftUI offers two views with this capability, ScrollView and List. In the previous post, we learned two ways to populate a list view's content.


1 Answers

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)
    }
}
like image 80
griff dog Avatar answered Oct 30 '22 06:10

griff dog