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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions