Repository navigation
Safe area: a bottom bar no longer jumps between two heights - #6129
shai-almog wants to merge 3 commits into
Conversation
A setSafeArea(true) container measured its preferred size from its current bounds and cached it. Measured before its first layout, or while its parent had moved and it had not, a bottom tab bar was sized for its content alone; layout then padded the bottom inset into that height and clipped the labels. Whichever later pass re-measured it put it back, so the bar jumped between the two layouts as the screen changed (Savor's customer tabs show it). Measurement now also counts the inset the last layout applied, and layout compares the inset it applies with the one measured, on any axis the parent sized from the preferred size; when they differ the size is measured again and the root lays out again in the same revalidate (bounded), so no frame paints the stale size. The inset arithmetic is a pure function, so the check writes no style and fires no extra events. Apps without display insets take no new path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
Cloudflare Preview
|
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 231 screenshots: 231 matched. |
|
Compared 210 screenshots: 210 matched. Benchmark ResultsDetailed Performance Metrics
ParparVM vs HotSpot (JDK 25): Windows x64Runner CPU: AMD64 Family 25 Model 17 Stepping 1, AuthenticAMD (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
|
Compared 210 screenshots: 210 matched. Benchmark ResultsDetailed Performance Metrics
ParparVM vs HotSpot (JDK 25): Windows arm64Runner CPU: ARMv8 (64-bit) Family 8 Model D49 Revision 0, MICROSOFT CORPORATION (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
|
Compared 206 screenshots: 206 matched. ParparVM vs HotSpot (JDK 25): Linux x64Runner CPU: AMD EPYC 9V74 80-Core Processor (baseline 1 improvement past the baseline (not a failure; rebaseline to lock it in):
Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
A change that moves performance ON PURPOSE records the new baseline in Result: no regression (improved past the baseline: consider rebaselining) |
|
Compared 210 screenshots: 210 matched. ParparVM vs HotSpot (JDK 25): Linux arm64Runner CPU: Neoverse-N2 (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
|
Compared 196 screenshots: 196 matched. Benchmark Results
Detailed Performance Metrics
ParparVM vs HotSpot (JDK 25): macOS arm64Runner CPU: Apple M1 (Virtual) (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
|
Compared 188 screenshots: 188 matched. Benchmark Results
Detailed Performance Metrics
|
Master's #6106 suppresses the snap's padding events and flags the container for re-measure instead. Folded into the split snap: during measurement only nested containers are flagged, so the size just measured is kept and the stale-inset check can run. Measurement now uses the inset the last layout applied (or the first reading in a new safe-area context) rather than the position read mid-layout, which can be stale in either direction. The context (safe margins and surface size) is recorded so rotation, a new safe area, hiding or re-adding the bar re-reads its position. New tests cover a bar pushed off the edge, partly over it, and a display gaining an inset after layout. Goldens: Android SheetSlideUpAnimation and the iOS metal-27 animation filmstrips, where bars measured before placement are now sized with their inset (the toolbar matches its height in the static screenshots). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 195 screenshots: 195 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
The snippet compiled only with an undeclared resourceFile, and master's edit of it left a baseline entry for a hash that no longer exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Native fidelity (ios-27-metal)68 pairs compared -- median 94.6%, worst 74.5% ( Distribution --
Geometry vs native (bbox offset / size ratio / center offset / corner radius) -- gated separately from the visual score
Side-by-side comparisons (worst first)
|
Native fidelity (Android, Material 3)54 pairs compared -- median 95.6%, worst 91.3% ( Distribution --
Geometry vs native (bbox offset / size ratio / center offset / corner radius) -- gated separately from the visual score
Side-by-side comparisons (worst first)
|
















































































































































































































































Problem
A
setSafeArea(true)bottom tab bar (Savor's customer tabs, and customer apps) jumped between two layouts on tab switches: sized for its content plus the bottom inset, or sized for the content alone with the inset padded inside it, clipping the labels.Container.calcPreferredSizejudged the inset from the container's current bounds and cached the result. Measured before its first layout, or mid-layout after its parent moved but before it was placed, the bar got no inset, and nothing made layout reconsider; whichever later pass happened to re-measure it put the inset back.Fix (
Container.java)safeAreaPadding(); the snap applies it.Tests
SafeAreaBottomBarStabilityTest(core-unittests): tab switches, a bar above it appearing/going, safe area removed, bar moved to the top, safe-area bar inside a safe-area pane (one inset), and one layout per revalidate for a settled bar, a stretched pane and a scrollable pane (whose scroll size keeps the inset). Three fail on master (bar 28px instead of 62px).Locally: core-unittests 8249 tests green, SpotBugs 0, PMD 0.
🤖 Generated with Claude Code