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)

Abierto
#555 0 comentarios 1 reacción 0 asignados Ver en GitHub
Lenguaje dominante
TypeScript
Estrellas
1.5k
Forks
109
Merge medio
11 h 44 min
PR fusionados (30 d)
8

Descripción

## 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.

Tab screen content latched at ~40% of the window with dead space below; tab bar and floating elements unaffected

## 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)

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

Comienza en RCTTabView.kt siguiendo el listener de cambios de layout, su comprobación de tamaño y las dimensiones de layoutHolder notificadas a JS. Reproduce el escenario de altura transitoria descrito en el issue e inspecciona los trazados de Logcat o la reproducción del PR enlazado. Se considera terminado cuando se notifica un cambio posterior del tamaño de layoutHolder y las pantallas de las pestañas dejan de permanecer recortadas durante la sesión.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
android, kotlin, react-native
Área
mobile
Tipo de issue
Error
Dificultad
3/5
Tiempo estimado
1-2 días
Estado de actividad
Tranquilo
Claridad
Bien especificado
Aptitud para principiantes
74/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.