callstack / callstack/react-native-bottom-tabs
[Android] Tab screens stay clipped at a transient startup height for the whole session (onNativeLayout guard/report size mismatch)
- Lingua principale
- TypeScript
- Stelle
- 1.5k
- Fork
- 109
- Merge medio
- 11h 44m
- PR unite (30g)
- 8
Descrizione
## Description
On Android, tab screens can get stuck clipped to a fraction of the window for the entire session: content renders in the top ~half of the screen with dead space below, while the tab bar, absolutely-positioned siblings, and pushed stack screens render normally. A force-close sometimes clears it; the race is per cold start. We observed this persistently in production on a Pixel 6a / Android 16.
## Root cause
In `RCTTabView.kt`, the layout-change listener guards re-reporting on the **outer** view's size but reports the **inner** `layoutHolder`'s size to JS:
```kotlin
val newWidth = right - left // outer view (guard)
val newHeight = bottom - top
...
val dpHeight = Utils.convertPixelsToDp(context, layoutHolder.height) // inner view (report)
...
lastReportedSize = Size(newWidth, newHeight) // stores outer size
```
During startup the outer frame can settle at its final size while `layoutHolder` is still mid-layout at a transient height. If the listener fires in that window, the transient height is reported to JS and the **outer** size is latched into `lastReportedSize`. When `layoutHolder` finishes laying out, the outer size hasn't changed, so the guard never allows a re-report — the transient height is styled onto every tab screen for the rest of the session.
Regression from #283, which switched the *reported* size to `layoutHolder` without switching the *guard*.
## Reproduction
Timing-dependent in the wild, but deterministic if you simulate the transient: force `layoutHolder` to a non-final height when the listener first fires, then restore it (snippet in the linked PR). On current `main` this latches the transient height with no further report; screens stay clipped. Logcat traces for both before and after the fix are in the PR.
## Fix
Key the guard on `layoutHolder`'s own dimensions — the same view whose size is reported — so any later correct layout is detected and re-reported (self-heals in a single frame; 5 ms measured in our repro). PR incoming.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Start in RCTTabView.kt by tracing the layout-change listener, its size guard, and the layoutHolder dimensions reported to JS. Reproduce the transient-height scenario described in the issue and inspect the Logcat traces or linked PR reproduction. Done means a later layoutHolder size change is reported and tab screens no longer remain clipped for the session.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- android, kotlin, react-native
- Ambito
- mobile
- Tipo di issue
- Bug
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 74/100