Skip to content

Commit 3308b62

Browse files
committed
feat: data binding add trigger property hook
1 parent b7050e6 commit 3308b62

5 files changed

Lines changed: 83 additions & 6 deletions

File tree

android/src/main/java/com/rivereactnative/RiveReactNativeView.kt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import kotlinx.coroutines.Dispatchers
3636
import kotlinx.coroutines.Job
3737
import kotlinx.coroutines.SupervisorJob
3838
import kotlinx.coroutines.cancel
39+
import kotlinx.coroutines.flow.drop
3940
import kotlinx.coroutines.launch
4041
import java.io.IOException
4142
import java.io.InputStream
@@ -453,10 +454,20 @@ class RiveReactNativeView(private val context: ThemedReactContext) : FrameLayout
453454
RNPropertyType.Color -> viewModelInstance.getColorProperty(path)
454455
RNPropertyType.Enum -> viewModelInstance.getEnumProperty(path)
455456
RNPropertyType.Trigger -> viewModelInstance.getTriggerProperty(path)
456-
} ?: return
457+
}
457458
val job = scope.launch {
458-
property.valueFlow.collect { value ->
459-
sendEvent(key, value)
459+
when (propertyTypeEnum) {
460+
RNPropertyType.Trigger -> {
461+
// We drop the first value as a trigger has no initial value
462+
property.valueFlow.drop(1).collect { _ ->
463+
sendEvent(key, null)
464+
}
465+
}
466+
else -> {
467+
property.valueFlow.collect { value ->
468+
sendEvent(key, value)
469+
}
470+
}
460471
}
461472
}
462473
propertyListeners[key] = PropertyListener(viewModelInstance, path, propertyType, job)

example/app/(examples)/DataBinding.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import Rive, {
2020
useRiveColor,
2121
useRiveNumber,
2222
useRiveString,
23+
useRiveTrigger,
2324
} from 'rive-react-native';
2425
import { Button } from 'react-native-paper';
2526
import { useNavigation } from '@react-navigation/native';
@@ -34,6 +35,10 @@ export default function DataBinding() {
3435
let [price, setPrice] = useRiveNumber(riveRef, 'Price_Value');
3536
let [coinValue] = useRiveNumber(riveRef, 'Coin/Item_Value');
3637

38+
useRiveTrigger(riveRef, 'Button/Pressed', () => {
39+
console.log('Button pressed');
40+
});
41+
3742
useEffect(() => {
3843
if (coinValue !== undefined) {
3944
console.log('coinValue changed:', coinValue);

ios/RiveReactNativeView.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
676676

677677
private struct PropertyRegistration {
678678
let property: RiveDataBindingViewModel.Instance.Property
679-
let initialValue: Any
679+
let initialValue: Any?
680680
let createListener: () -> UUID?
681681
}
682682

@@ -751,7 +751,16 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
751751
)
752752

753753
case .Trigger:
754-
return nil
754+
guard let prop = dataBindingInstance.triggerProperty(fromPath: path) else { return nil }
755+
return PropertyRegistration(
756+
property: prop,
757+
initialValue: nil,
758+
createListener: { [weak self] in
759+
prop.addListener {
760+
self?.eventEmitter?.sendEvent(withName: key, body: nil)
761+
}
762+
}
763+
)
755764
}
756765
}()
757766

@@ -763,7 +772,9 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
763772
}
764773

765774
// Send initial value
766-
eventEmitter?.sendEvent(withName: key, body: registration.initialValue)
775+
if let initialValue = registration.initialValue {
776+
eventEmitter?.sendEvent(withName: key, body: initialValue)
777+
}
767778

768779
// Create and store listener
769780
if let listener = registration.createListener() {

src/Rive.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,54 @@ export function useRiveColor(
207207
return useRivePropertyListener<RiveRGBA>(riveRef, path, PropertyType.Color);
208208
}
209209

210+
export function useRiveTrigger(
211+
riveRef: RiveRef | null,
212+
path: string,
213+
onTrigger?: () => void
214+
): (() => void) | undefined {
215+
const triggerCallback = useCallback(() => {
216+
onTrigger?.();
217+
}, [onTrigger]);
218+
219+
useEffect(() => {
220+
const listener = riveRef?.internalNativeEmitter?.();
221+
if (!listener) return () => {};
222+
const reactTag = findNodeHandle(riveRef.viewTag());
223+
if (!reactTag) return () => {};
224+
225+
listener.addListener<void>(
226+
path,
227+
PropertyType.Trigger,
228+
reactTag,
229+
triggerCallback
230+
);
231+
232+
return () => {
233+
listener.removeListener<void>(
234+
path,
235+
PropertyType.Trigger,
236+
reactTag,
237+
triggerCallback
238+
);
239+
};
240+
}, [riveRef, path, triggerCallback]);
241+
242+
// Function to fire the trigger
243+
const trigger = useCallback(() => {
244+
if (!riveRef) {
245+
if (__DEV__) {
246+
console.warn(
247+
`[Rive] Tried to trigger "${path}" before riveRef was available.`
248+
);
249+
}
250+
return;
251+
}
252+
riveRef.trigger(path);
253+
}, [riveRef, path]);
254+
255+
return riveRef ? trigger : undefined;
256+
}
257+
210258
function useRivePropertyListener<T>(
211259
riveRef: RiveRef | null,
212260
path: string,

src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Rive, {
77
useRiveBoolean,
88
useRiveColor,
99
useRiveEnum,
10+
useRiveTrigger,
1011
} from './Rive';
1112

1213
export {
@@ -17,6 +18,7 @@ export {
1718
useRiveBoolean,
1819
useRiveColor,
1920
useRiveEnum,
21+
useRiveTrigger,
2022
};
2123

2224
export default Rive;

0 commit comments

Comments
 (0)