rive-app / rive-app/rive-android
Fit.LAYOUT artboard size incorrect when onMeasure is deferred or state machine animates artboard width
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 538
- Forks
- 66
- PR merge metrics
- No merged PRs in 30d
Description
Description
Fit.LAYOUT artboard size is incorrect under two conditions:
-
layoutScaleFactorAutomaticdefaults to1.0and is only set to device density inonMeasure(). Since the view hasn't been measured yet whensetRiveFile()is called,resizeArtboard()computespixelWidth / 1.0instead ofpixelWidth / density— the artboard ends up density× too wide. iOS avoids this by initializing the scale factor at view init time. Originally reported in rive-nitro-react-native#206, simple workaround possible by settinglayoutScaleFactorto density beforesetRiveFile. -
When a state machine animates the artboard width: keyframes overwrite
m_Widthevery frame viaCoreRegistry::setDouble(artboard, widthPropertyKey, ...)duringadvance(). SinceresizeArtboard()only runs once (one-shotrequireArtboardResizeflag), the artboard stays at the keyframe value.
For reference, the iOS runtime approaches this differently: it initializes scale factor at view init time and re-applies artboard dimensions every frame in drawRive rather than using a one-shot flag. It also re-applies on size change in drawableSizeDidChange. Not saying this is necessarily the right approach for Android, but it avoids both issues above.
Versions, Device, and Other Information
- Rive Android Runtime Version: 11.3.2
- Rive API: Legacy (View-based)
- Device: Android API 35 emulator (1080x2220, 440dpi), also reported on OnePlus CPH2719, Samsung Galaxy Fold 3
- App Minimum SDK Level: 21
- App Target SDK Level: 36
- Frequency: Issue 1 — 100% when setRiveFile is called before onMeasure. Issue 2 — 9/10 with layout_test.riv.
Reproduction Steps
Issue 1 (scale factor default): Any .riv with Fit.LAYOUT. The view hasn't been measured when setRiveFile is called, so layoutScaleFactorAutomatic is still 1.0. Confirmed via logcat:
configure: reload=true fit=LAYOUT viewSize=0x0px
configure post-setRiveFile: artboardW=1920.0 artboardH=1080.0
onLayout: artboardW=1920.0 artboardH=1080.0 ← still intrinsic size after layout
Reproduced in bare Android by suppressing onMeasure:
✗ Artboard 1080 dp ≠ View 393 dp (2.8x too wide!)
The 2.75x factor matches exactly the device density — 1080px / 1.0 instead of 1080px / 2.75.
Issue 2 (keyframe overwrite): layout_test.riv with Fit.LAYOUT — the state machine animates the artboard width property, overwriting the value set by resizeArtboard() every frame. Reproduced 9/10 launches.
Source .riv/.rev File
- Issue 1: Any
.rivwithFit.LAYOUT(tested withGradientBorder.rivfrom user's repro) - Issue 2:
layout_test.rivfrom rive-android example app
Expected Behavior
Artboard dimensions should match viewWidth / density for Fit.LAYOUT.
Screenshots
Additional context
For reference, iOS handles this in:
RiveView.swift L38-44— scale factor initialized at view initdrawRiveL446-452 — artboard dimensions re-applied every framedrawableSizeDidChangeL490-501 — re-applied on size change
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the Android view's setRiveFile(), onMeasure(), resizeArtboard(), and requireArtboardResize flow, then inspect how advance() updates the artboard width. Reproduce both cases with Fit.LAYOUT, including layout_test.riv from the example app. Done means the artboard matches viewWidth/density before measurement and remains correctly sized while the state machine animates.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100