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)
- Langage dominant
- TypeScript
- Étoiles
- 1.5k
- Forks
- 109
- Merge moyen
- 11 h 44 min
- PR mergées (30 j)
- 8
Description
## 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)
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Commencez dans RCTTabView.kt en suivant le listener de changement de layout, sa vérification de taille et les dimensions de layoutHolder signalées à JS. Reproduisez le scénario de hauteur transitoire décrit dans l’issue et examinez les traces Logcat ou la reproduction du PR lié. Le travail est terminé lorsqu’une modification ultérieure de la taille de layoutHolder est signalée et que les écrans des onglets ne restent plus tronqués pendant la session.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- android, kotlin, react-native
- Domaine
- mobile
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- Calme
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 74/100