@@ -7,7 +7,7 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
77 private var eventEmitter : RiveReactNativeEventModule ? {
88 return self . bridge? . module ( for: RiveReactNativeEventModule . self) as? RiveReactNativeEventModule
99 }
10- private var propertyListeners : [ ( key : String , property : RiveDataBindingViewModel . Instance . Property , listener : UUID ) ] = [ ]
10+ private var propertyListeners : [ String : PropertyListener ] = [ : ]
1111 private var dataBindingConfig : DataBindingConfig ?
1212
1313 // MARK: RiveReactNativeView Properties
@@ -146,10 +146,11 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
146146 if let loadedTag = generateLoadedTag ( ) {
147147 eventEmitter? . removeListener ( byName: loadedTag)
148148 }
149- propertyListeners. forEach { ( key: String , property : RiveDataBindingViewModel . Instance . Property , listener : UUID ) in
150- property. removeListener ( listener)
149+ propertyListeners. forEach { ( key, value ) in
150+ value . property. removeListener ( value . listener)
151151 eventEmitter? . removeListener ( byName: key)
152152 }
153+ propertyListeners. removeAll ( )
153154 dataBindingViewModelInstance = nil
154155 }
155156
@@ -213,12 +214,22 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
213214
214215 private func configureDataBinding( viewModel: RiveViewModel ) {
215216 guard let artboard = viewModel. riveModel? . artboard,
216- let dataBindingViewModel = viewModel. riveModel? . riveFile. defaultViewModel ( for: artboard) else { return }
217+ let dataBindingViewModel = viewModel. riveModel? . riveFile. defaultViewModel ( for: artboard) else { return }
217218
218219 func bindInstance( _ instance: RiveDataBindingViewModel . Instance ? ) {
219220 guard let instance = instance else { return }
220221 viewModel. riveModel? . stateMachine? . bind ( viewModelInstance: instance)
221222 self . dataBindingViewModelInstance = instance
223+
224+ // As we can't control whether `configureDataBinding` is called
225+ // before/after/between `registerPropertyListener` (if it is called again) we
226+ // re-add the current registered listeners if the instance is not the same
227+ // to ensure they are attached to the current active dataBindingViewModelInstance
228+ propertyListeners. forEach { ( _, value) in
229+ if ( value. dataBindingInstance != self . dataBindingViewModelInstance) {
230+ registerPropertyListener ( path: value. path, propertyType: value. propertyType)
231+ }
232+ }
222233 }
223234
224235 switch dataBindingConfig {
@@ -230,12 +241,16 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
230241 } else {
231242 viewModel. riveModel? . disableAutoBind ( )
232243 }
244+ break
233245 case . index( let index) :
234246 bindInstance ( dataBindingViewModel. createInstance ( fromIndex: UInt ( index) ) )
247+ break
235248 case . name( let name) :
236249 bindInstance ( dataBindingViewModel. createInstance ( fromName: name) )
250+ break
237251 case . empty:
238252 bindInstance ( dataBindingViewModel. createInstance ( ) )
253+ break
239254 case nil :
240255 break
241256 }
@@ -633,82 +648,110 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
633648 dataBindingViewModelInstance? . triggerProperty ( fromPath: path) ? . trigger ( )
634649 }
635650
636- private func storeProperty( key: String , property : RiveDataBindingViewModel . Instance . Property ? , listener : UUID ? ) {
637- if let property = property , let listener = listener {
638- propertyListeners . append ( ( key : key , property : property , listener : listener ) )
651+ private func storeProperty( key: String , propertyListener : PropertyListener ) {
652+ if let existingListener = propertyListeners [ key ] ? . listener , let existingProperty = propertyListeners [ key ] ? . property {
653+ existingProperty . removeListener ( existingListener )
639654 }
655+ propertyListeners [ key] = propertyListener
656+ }
657+
658+ private struct PropertyRegistration {
659+ let property : RiveDataBindingViewModel . Instance . Property
660+ let initialValue : Any
661+ let createListener : ( ) -> UUID ?
640662 }
641663
642664 func registerPropertyListener( path: String , propertyType: String ) {
643- guard let reactTag = self . reactTag else { return }
665+ guard let reactTag = self . reactTag,
666+ let dataBindingInstance = dataBindingViewModelInstance,
667+ let propertyTypeEnum = safePropertyType ( propertyType) else { return }
668+
644669 let key = " \( propertyType) : \( path) : \( reactTag) "
645- let propertyTypeEnum = safePropertyType ( propertyType)
646- switch propertyTypeEnum {
647- case . String:
648- let stringProperty = dataBindingViewModelInstance? . stringProperty ( fromPath: path)
649- if let initialValue = stringProperty? . value {
650- eventEmitter? . sendEvent ( withName: key, body: initialValue)
651- }
652- let listener = stringProperty? . addListener { [ weak self] newValue in
653- self ? . eventEmitter? . sendEvent ( withName: key, body: newValue)
654- }
655- storeProperty ( key: key, property: stringProperty, listener: listener)
656- case . Boolean:
657- let booleanProperty = dataBindingViewModelInstance? . booleanProperty ( fromPath: path)
658- if let initialValue = booleanProperty? . value {
659- eventEmitter? . sendEvent ( withName: key, body: initialValue)
660- }
661- let listener = booleanProperty? . addListener { [ weak self] newValue in
662- self ? . eventEmitter? . sendEvent ( withName: key, body: newValue)
663- }
664- storeProperty ( key: key, property: booleanProperty, listener: listener)
665- case . Number:
666- let numberProperty = dataBindingViewModelInstance? . numberProperty ( fromPath: path)
667- if let initialValue = numberProperty? . value {
668- eventEmitter? . sendEvent ( withName: key, body: initialValue)
669- }
670- let listener = numberProperty? . addListener { [ weak self] newValue in
671- self ? . eventEmitter? . sendEvent ( withName: key, body: newValue)
672- }
673- storeProperty ( key: key, property: numberProperty, listener: listener)
674- case . Color:
675- let colorProperty = dataBindingViewModelInstance? . colorProperty ( fromPath: path)
676- if let initialValue = colorProperty? . value {
677- eventEmitter? . sendEvent ( withName: key, body: colorToHexInt ( initialValue) )
678- }
679- let listener = colorProperty? . addListener { [ weak self] newValue in
680- self ? . eventEmitter? . sendEvent ( withName: key, body: self ? . colorToHexInt ( newValue) )
681- }
682- storeProperty ( key: key, property: colorProperty, listener: listener)
683- case . Enum:
684- let enumProperty = dataBindingViewModelInstance? . enumProperty ( fromPath: path)
685- if let initialValue = enumProperty? . value {
686- eventEmitter? . sendEvent ( withName: key, body: initialValue)
687- }
688- let listener = enumProperty? . addListener { [ weak self] newValue in
689- self ? . eventEmitter? . sendEvent ( withName: key, body: newValue)
670+
671+ // Get registration info based on property type
672+ let registration : PropertyRegistration ? = {
673+ switch propertyTypeEnum {
674+ case . String:
675+ guard let prop = dataBindingInstance. stringProperty ( fromPath: path) else { return nil }
676+ return PropertyRegistration (
677+ property: prop,
678+ initialValue: prop. value,
679+ createListener: { [ weak self] in
680+ prop. addListener { newValue in
681+ self ? . eventEmitter? . sendEvent ( withName: key, body: prop. value)
682+ }
683+ }
684+ )
685+
686+ case . Boolean:
687+ guard let prop = dataBindingInstance. booleanProperty ( fromPath: path) else { return nil }
688+ return PropertyRegistration (
689+ property: prop,
690+ initialValue: prop. value,
691+ createListener: { [ weak self] in
692+ prop. addListener { newValue in
693+ self ? . eventEmitter? . sendEvent ( withName: key, body: prop. value)
694+ }
695+ }
696+ )
697+
698+ case . Number:
699+ guard let prop = dataBindingInstance. numberProperty ( fromPath: path) else { return nil }
700+ return PropertyRegistration (
701+ property: prop,
702+ initialValue: prop. value,
703+ createListener: { [ weak self] in
704+ prop. addListener { newValue in
705+ self ? . eventEmitter? . sendEvent ( withName: key, body: prop. value)
706+ }
707+ }
708+ )
709+
710+ case . Color:
711+ guard let prop = dataBindingInstance. colorProperty ( fromPath: path) else { return nil }
712+ return PropertyRegistration (
713+ property: prop,
714+ initialValue: prop. value. toHexInt ( ) ,
715+ createListener: { [ weak self] in
716+ prop. addListener { newValue in
717+ self ? . eventEmitter? . sendEvent ( withName: key, body: prop. value. toHexInt ( ) )
718+ }
719+ }
720+ )
721+
722+ case . Enum:
723+ guard let prop = dataBindingInstance. enumProperty ( fromPath: path) else { return nil }
724+ return PropertyRegistration (
725+ property: prop,
726+ initialValue: prop. value,
727+ createListener: { [ weak self] in
728+ prop. addListener { newValue in
729+ self ? . eventEmitter? . sendEvent ( withName: key, body: prop. value)
730+ }
731+ }
732+ )
733+
734+ case . Trigger:
735+ return nil
690736 }
691- storeProperty ( key: key, property: enumProperty, listener: listener)
692- case . Trigger: break
693- case . none: break
694- }
695- }
696-
697- func colorToHexInt( _ color: UIColor ) -> Int {
698- var red : CGFloat = 0
699- var green : CGFloat = 0
700- var blue : CGFloat = 0
701- var alpha : CGFloat = 0
737+ } ( )
702738
703- color . getRed ( & red , green : & green , blue : & blue , alpha : & alpha )
739+ guard let reg = registration else { return }
704740
705- let r = UInt32 ( red * 255 )
706- let g = UInt32 ( green * 255 )
707- let b = UInt32 ( blue * 255 )
708- let a = UInt32 ( alpha * 255 )
741+ // Send initial value
742+ eventEmitter? . sendEvent ( withName: key, body: reg. initialValue)
709743
710- let hex = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b
711- return Int ( hex)
744+ // Create and store listener
745+ if let listener = reg. createListener ( ) {
746+ let propertyListener = PropertyListener (
747+ dataBindingInstance: dataBindingInstance,
748+ property: reg. property,
749+ listener: listener,
750+ path: path,
751+ propertyType: propertyType
752+ )
753+ storeProperty ( key: key, propertyListener: propertyListener)
754+ }
712755 }
713756
714757 // MARK: - StateMachineDelegate
@@ -839,11 +882,37 @@ class RiveReactNativeView: RCTView, RivePlayerDelegate, RiveStateMachineDelegate
839882 RCTLogError ( error. localizedDescription)
840883 }
841884 }
885+
886+ private enum DataBindingConfig {
887+ case autoBind( Bool )
888+ case index( Int )
889+ case name( String )
890+ case empty
891+ }
892+
893+ private struct PropertyListener {
894+ let dataBindingInstance : RiveDataBindingViewModel . Instance
895+ let property : RiveDataBindingViewModel . Instance . Property
896+ let listener : UUID
897+ let path : String
898+ let propertyType : String
899+ }
842900}
843901
844- enum DataBindingConfig {
845- case autoBind( Bool )
846- case index( Int )
847- case name( String )
848- case empty
902+ extension UIColor {
903+ func toHexInt( ) -> Int {
904+ var red : CGFloat = 0
905+ var green : CGFloat = 0
906+ var blue : CGFloat = 0
907+ var alpha : CGFloat = 0
908+
909+ self . getRed ( & red, green: & green, blue: & blue, alpha: & alpha)
910+
911+ let r = UInt32 ( red * 255 )
912+ let g = UInt32 ( green * 255 )
913+ let b = UInt32 ( blue * 255 )
914+ let a = UInt32 ( alpha * 255 )
915+
916+ return Int ( ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b)
917+ }
849918}
0 commit comments