Skip to content

Commit 05c4e71

Browse files
committed
fix(android): byName dataBind uses artboard default ViewModel, not vmNames.first()
Previously always picked the first ViewModel in the file; now uses DefaultForArtboard like the Auto path and iOS, so the correct ViewModel is selected regardless of ordering. Also removes the runBlocking call. Added harness test: artboard2+byName(vmi1) must yield _id=vm2.vmi1.id.
1 parent ab35d66 commit 05c4e71

2 files changed

Lines changed: 63 additions & 8 deletions

File tree

android/src/new/java/com/rive/RiveReactNativeView.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -315,14 +315,11 @@ class RiveReactNativeView(context: ThemedReactContext) : FrameLayout(context) {
315315
}
316316
is BindData.ByName -> {
317317
try {
318-
val vmNames = kotlinx.coroutines.runBlocking { riveFile.getViewModelNames() }
319-
if (vmNames.isNotEmpty()) {
320-
val vmSource = ViewModelSource.Named(vmNames.first())
321-
val source = vmSource.namedInstance(bindData.name)
322-
val instance = ViewModelInstance.fromFile(riveFile, source)
323-
boundInstance = instance
324-
bindInstanceToStateMachine(instance)
325-
}
318+
val art = artboard ?: return
319+
val source = ViewModelSource.DefaultForArtboard(art).namedInstance(bindData.name)
320+
val instance = ViewModelInstance.fromFile(riveFile, source)
321+
boundInstance = instance
322+
bindInstanceToStateMachine(instance)
326323
} catch (e: Exception) {
327324
Log.e(TAG, "Failed to create named instance", e)
328325
}

example/__tests__/viewmodel-instance-lookup.harness.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ import {
99
import { useEffect } from 'react';
1010
import { Platform, Text, View } from 'react-native';
1111
import {
12+
DataBindByName,
13+
Fit,
1214
RiveFileFactory,
15+
RiveView,
1316
ArtboardByName,
1417
useViewModelInstance,
1518
type RiveFile,
19+
type RiveViewRef,
1620
} from '@rive-app/react-native';
1721
import type { ViewModelInstance } from '@rive-app/react-native';
1822

@@ -490,3 +494,57 @@ describe('useViewModelInstance onInit verifies _id', () => {
490494
cleanup();
491495
});
492496
});
497+
498+
// ── dataBind byName uses artboard's default ViewModel ───────────────
499+
// Regression for Android bug: ByName was always creating the instance from
500+
// vmNames.first() instead of the artboard's default ViewModel. artboard2's
501+
// default is viewmodel2 (not viewmodel1), so _id must be "vm2.vmi1.id".
502+
503+
type ByNameCtx = { ref: RiveViewRef | null };
504+
505+
function ByNameView({
506+
file,
507+
artboardName,
508+
instanceName,
509+
ctx,
510+
}: {
511+
file: RiveFile;
512+
artboardName: string;
513+
instanceName: string;
514+
ctx: ByNameCtx;
515+
}) {
516+
return (
517+
<View style={{ width: 200, height: 200 }}>
518+
<RiveView
519+
hybridRef={{ f: (r: RiveViewRef | null) => { ctx.ref = r; } }}
520+
style={{ flex: 1 }}
521+
file={file}
522+
artboardName={artboardName}
523+
stateMachineName="State Machine 1"
524+
dataBind={new DataBindByName(instanceName)}
525+
fit={Fit.Contain}
526+
/>
527+
</View>
528+
);
529+
}
530+
531+
describe('dataBind byName uses artboard default ViewModel', () => {
532+
it('artboard2 + byName("vmi1") → _id="vm2.vmi1.id" (not vm1)', async () => {
533+
const file = await loadFile();
534+
const ctx: ByNameCtx = { ref: null };
535+
await render(
536+
<ByNameView
537+
file={file}
538+
artboardName="artboard2"
539+
instanceName="vmi1"
540+
ctx={ctx}
541+
/>
542+
);
543+
await waitFor(() => expect(ctx.ref).not.toBeNull(), { timeout: 5000 });
544+
await ctx.ref!.awaitViewReady();
545+
const instance = ctx.ref!.getViewModelInstance();
546+
expect(instance).toBeDefined();
547+
expect(instance!.stringProperty('_id')?.value).toBe('vm2.vmi1.id');
548+
cleanup();
549+
});
550+
});

0 commit comments

Comments
 (0)