[iOS][Fabric] RTL horizontal ScrollView: contentOffset prop is not RTL-converted while scrollTo/metrics are, and scrollTo conversion uses stale contentSize
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 42/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- ios, objective-c
- Ambito
- mobile-dev
Direzione di ricerca
Inizia in React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm, confrontando updateProps:, prepareForRecycle, il ripristino dello stato, scrollToOffset:animated: e _scrollViewMetrics. Usa i passaggi di riproduzione RTL Fabric elencati per osservare gli offset delle prop e gli offset imperativi prima e dopo le modifiche al contenuto. Il lavoro è completato quando gli input degli offset RTL si comportano in modo coerente e il timing delle dimensioni del contenuto non causa più discrepanze di pagina non documentate, con il comportamento rilevante coperto o chiaramente documentato.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Description
On the New Architecture (Fabric), iOS implements RTL for a horizontal ScrollView by mirroring the view and converting scroll coordinates — but the conversion is asymmetric, and the imperative conversion depends on the native contentSize being current at call time. JS-driven paged lists that work on Paper break on Fabric under RTL.
In React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm (0.81.5; the same code is on main and 0.82-stable):
updateLayoutMetrics:appliesCGAffineTransformMakeScale(-1, 1)to_containerViewand_scrollViewwhenlayoutDirection == RightToLeft._scrollViewMetricsconverts the reported offset:metrics.contentOffset.x = contentSize.width - containerSize.width - contentOffset.x(RTL branch).scrollToOffset:animated:converts the requested offset:offset.x = self.contentSize.width - _scrollView.frame.size.width - offset.x(RTL branch) —main~L1024.updateProps:applies thecontentOffsetprop with no conversion:_scrollView.contentOffset = RCTCGPointFromPoint(newScrollViewProps.contentOffset)—main~L408. TheprepareForRecycle/ state-restore paths setcontentOffsetunconverted too.
Two concrete consequences:
- Prop vs. imperative disagree. In RTL,
contentOffset={{x: k * pageWidth}}positions the view in physical (mirrored) space, whilescrollTo({x: k * pageWidth})positions it in logical space (andonScrollreports logical). For a paged list the prop lands one page off / at the far end relative to an identicalscrollTo. scrollTois timing-dependent. The conversion usesself.contentSize.widthand_scrollView.frame.size.widthat call time. AscrollToissued right after content changes (before the nativecontentSizecommits — e.g. in asetTimeout(0)after a data update, a very common pattern) is converted with stale dimensions and lands on the wrong page. This never happened in LTR (no conversion) and did not happen on Paper, so it surfaces as intermittent, device-only page jumps.
Steps to reproduce
- RTL app:
I18nManager.allowRTL(true); I18nManager.forceRTL(true)and cold launch (the direction is read at startup). newArchEnabled: true, iOS.- Horizontal
ScrollViewwithpagingEnabled, N full-width pages. - Case A — set
contentOffset={{x: k * width}}as a prop; compare the page shown with callingscrollTo({x: k * width, animated: false})after mount: they show different pages. - Case B — change the content (add/remove pages) and in the same tick /
setTimeout(0)callscrollTo({x: k * width}): on a device it frequently lands on a different page thank(converted against the previouscontentSize); readingcontentOffset.xfrom the nextonScrollconfirms the mismatch.
Expected behavior
All offset inputs are converted consistently in RTL — the contentOffset prop (and recycle/state restore) using the same mapping as scrollToOffset: and _scrollViewMetrics — and the imperative conversion should not silently use a stale contentSize (or the behavior should be documented so libraries can wait for the commit).
React Native Version
0.81.5 (Expo SDK 54). Verified the same code paths on main and 0.82-stable.
Affected Platforms
Runtime - iOS (New Architecture / Fabric). Not reproducible on the old architecture; not affected in LTR.
Environment
macOS 15 (Darwin 24.2), Xcode 16.2, iPhone 12 simulator (iOS 18.2) and physical iPhone (iOS 26.3.1), Hermes, newArchEnabled: true.
Real-world impact
react-native-calendars (used widely for RTL calendars) implements its own RTL offset handling for its recyclerlistview-based horizontal pagers; on Fabric that handling — and a naive "just remove the inversion" fix — both fail because of the two points above, producing calendars that jump between days/weeks nonstop. A downstream workaround (keep the pager's container direction: 'ltr' and mirror in JS) will be linked here.
Reproducer
No standalone reproducer repository attached yet; the steps above are minimal and the relevant native lines are cited. Happy to add a reproducer-react-native repo if maintainers want one.
- Lingua principale
- C++
- Stelle
- 127k
- Fork
- 25.3k
- Merge medio
- 1g 23h
- PR unite (30g)
- 4
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di react/react-native
-
Needs: Triage :mag:
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
react/react-native#58565 · 1 commento · 2 reazioni ·
-
Needs: Author Feedback Needs: Repro
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
react/react-native#58555 · 4 commenti · 1 reazione ·
-
Needs: Attention Needs: Repro
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
react/react-native#58526 · 2 commenti ·
-
Needs: Author Feedback Needs: Repro
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
react/react-native#58448 · 1 commento ·
-
Needs: Attention Needs: Repro
Difficoltà 2/5 Mezza giornata Idoneità per principianti 82/100
react/react-native#58441 · 2 commenti ·
Tutte le issue di react/react-native
Issue simili
-
Website Doc Typo Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 92/100
-
Difficoltà 1/5 1-3 ore Idoneità per principianti 92/100
autowarefoundation/autoware_universe#13413 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
automated-analysis bug memory-safety
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100