skiptools / skiptools/skip-ui

ScrollViewProxy.scrollTo animates long-distance scrolling on Android

Open
#469 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Swift
Stars
330
Forks
76
Avg merge
3h 6m
Merged PRs (30d)
1

Description

After upgrading skip-ui from 1.52.0 to 1.56.0, ScrollViewProxy.scrollTo(_:anchor:) on Android frequently performs an animated scroll instead of an instant jump, even when it is not wrapped in withAnimation.
This results in a long visible scroll through the entire list when navigating to items far away in large LazyVStack/List views.

Expected behavior

Calling:

proxy.scrollTo(id, anchor: .top)

outside of withAnimation should immediately jump to the target item (Compose scrollToItem behavior).

Repro
TabView(selection: $mode) {
    menuView.tag(Mode.menu)

    ScrollViewReader { proxy in
        ScrollView {
            LazyVStack {
                ForEach(items) { item in
                    Text(item.title)
                        .id(item.id)
                }
            }
        }
        .onChange(of: targetId) { _, newId in
            if let newId {
                Task { @MainActor in
                    try? await Task.sleep(for: .milliseconds(300))
                    proxy.scrollTo(newId, anchor: .top) // Not wrapped in withAnimation
                }
            }
        }
    }
    .tag(Mode.content)
}
.tabViewStyle(.page(indexDisplayMode: .never))

// Navigation
withAnimation {
    targetId = someItemId
    mode = .content
}

The navigation to the content page is intentionally animated, but the subsequent proxy.scrollTo call is not. Prior to 1.56.0, this resulted in an immediate jump to the target item. Since upgrading, the scroll itself is animated, suggesting that scrollTo is now using animateScrollToItem instead of scrollToItem in this scenario.

Is this an intentional change in behavior?
If so, is there currently a recommended workaround to force an immediate jump when calling proxy.scrollTo outside of withAnimation?

Additional testing

I patched LazyVStack.swift to always use scrollToItem instead of switching based on Animation.isInWithAnimation.
This restores the previous behavior: proxy.scrollTo immediately jumps to the target item, matching skip-ui 1.52.0.

If appropriate, would it make sense for the default behavior to use scrollToItem across lazy scroll containers, with an explicit API for animated scrolling when desired?

Thanks!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in LazyVStack.swift and trace how Animation.isInWithAnimation selects between scrollToItem and animateScrollToItem. Run the supplied ScrollViewReader reproduction with a large LazyVStack, then verify that scrollTo outside withAnimation jumps immediately while animated navigation remains unaffected.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
mobile-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.