Skip to content

Fit.LAYOUT artboard size incorrect when onMeasure is deferred or state machine animates artboard width #446

@mfazekas

Description

@mfazekas

Description

Fit.LAYOUT artboard size is incorrect under two conditions:

  1. layoutScaleFactorAutomatic defaults to 1.0 and is only set to device density in onMeasure(). Since the view hasn't been measured yet when setRiveFile() is called, resizeArtboard() computes pixelWidth / 1.0 instead of pixelWidth / 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 setting layoutScaleFactor to density before setRiveFile.

  2. When a state machine animates the artboard width: keyframes overwrite m_Width every frame via CoreRegistry::setDouble(artboard, widthPropertyKey, ...) during advance(). Since resizeArtboard() only runs once (one-shot requireArtboardResize flag), 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 .riv with Fit.LAYOUT (tested with GradientBorder.riv from user's repro)
  • Issue 2: layout_test.riv from rive-android example app

Expected Behavior

Artboard dimensions should match viewWidth / density for Fit.LAYOUT.

Screenshots

Additional context

For reference, iOS handles this in:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions