Skip to content

Open a list or virtual list at a row with auto-scroll-to - #174

Open
wojt-janowski wants to merge 1 commit into
NativePHP:mainfrom
wojt-janowski:fix/keep-list-position
Open

wojt-janowski wants to merge 1 commit into
NativePHP:mainfrom
wojt-janowski:fix/keep-list-position

Conversation

@wojt-janowski

@wojt-janowski wojt-janowski commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Problem

An app can't choose where a list opens. A screen restored after a relaunch, a deep link to a record, or a list that should show the record just added all open at row 0, and ScrollView::autoScrollTo() has no counterpart on native:list or native:virtual-list.

Change

auto-scroll-to (and autoScrollTo(int)) on native:list and native:virtual-list, named after ScrollView::autoScrollTo() and behaving like it:

  • The list jumps to the row when it is created, and scrolls (animated) only when the index changes. A re-render that carries the same index leaves the list where the reader scrolled it.
  • Rows count the way on-end-reached and on-visible-range count them: from 0, with a section's rows in their place. On Android the row is mapped to its lazy item past section headers, gaps, footers, sticky headers and a pager header. On iOS the row is found by its node id through ScrollViewReader. A virtual list's slot id is its absolute index.
  • On Android the request last applied is kept in rememberSaveable, so a list restored by going back isn't moved either. On iOS the modifier's @State lives as long as the level does.
  • A row that hasn't arrived yet (a page still loading) is scrolled to when it does.

For a virtual list the window has to hold the row. NativePHP/mobile-air#608 adds HasVirtualListWindow::scrollVirtualListTo(), which moves the window and sets $virtualScrollTo for :auto-scroll-to. The prop itself doesn't depend on that PR: with an explicit window it works on its own. This PR doesn't restore positions on back. On Android that is NativePHP/mobile-air#588 (preserving native screen state); iOS's NavigationStack already keeps the level below alive.

README and the Boost skill table document it.

Evidence

Firstlight showcase main (33aa94b), pointed at this branch and a mobile-air branch that, when these were captured, also carried an Android state-restore change since dropped in favour of #588. Android emulator API 37.2, iOS Simulator iPhone 17 Pro on iOS 27.0. Posts is a firstlight:list (which renders with this ListRenderer) with :auto-scroll-to="8". Contacts is a 5,000-row native:virtual-list whose mount() calls scrollVirtualListTo(2500).

Opens at the row on both platforms:

Opens at row

Doesn't fight the reader. After scrolling past the window, which triggers on-window-change re-renders, the list stays where it was scrolled rather than jumping back to the row. The shots also open a contact and go back: on iOS that is stock behaviour; on Android the kept place came from the state-restore change, now #588's job, so read the Android "back" panel as needing #588. Posts behaves the same while on-end-reached loads page 2. Reopening Posts from Recipes opens at row 8 again.

Doesn't fight

Tests: four new Pest cases in ListTest and CollectorElementsTest. The suite passes (407) and Pint is clean.

Not verified on a device: the animated re-scroll when PHP changes the index on a list that's already showing, horizontal lists, sectioned lists, lists under a pager header, and physical devices. I checked these index paths by reading the code, not by running them.

Reported from https://ampcode.com/threads/T-01a1717b-73af-7263-867e-a12595969c54

auto-scroll-to on native:list and native:virtual-list puts that row at the
top when the list is created, for a relaunch, a deep link or a new record.
It scrolls again only when the index changes, so re-renders don't pull the
list away from where the reader scrolled. The request last applied is saved
with the list, so a list restored by going back isn't moved either.

Rows count as end-reached and visible-range count them. Works on iOS and
Android.

Amp-Thread-ID: https://ampcode.com/threads/T-01a1724b-7f88-71f2-a62f-4eae107d3dda
Co-authored-by: Amp <amp@ampcode.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant