Native Animated - Support events using RCT{Direct|Bubbling}EventBlock on iOS (#15611)

Summary:
When calling a prop of type `RCTDirectEventBlock` or `RCTBubblingEventBlock` it uses a completely different code path than events using `[RCTEventDispatcher sendEvent:]` and those were not dispatched to the `RCTEventDispatcherListener`s. We also do some event name normalization which caused issues between the JS and native event names. To fix that I simply remove the parts we normalize from the event key.

## Changelog:

[iOS] [Fixed] - Support events using RCT{Direct|Bubbling}EventBlock
Pull Request resolved: https://github.com/facebook/react-native/pull/15611

Test Plan: Added a Slider (it used RCTBubblingEventBlock for it's onValueChange event) that can control a native animated value in RNTester to reproduce the bug and made sure this diff fixes it.

Differential Revision: D15896806

Pulled By: cpojer

fbshipit-source-id: c0ae463f4c3f890062238575e813ed7ab3b7a7e6
This commit is contained in:
Janic Duplessis 2019-06-19 01:39:10 -07:00 коммит произвёл Facebook Github Bot
Родитель a89e9323fc
Коммит 083f835c9f
2 изменённых файлов: 28 добавлений и 6 удалений

Просмотреть файл

@ -28,6 +28,21 @@
#import "RCTValueAnimatedNode.h"
#import "RCTTrackingAnimatedNode.h"
// We do some normalizing of the event names in RCTEventDispatcher#RCTNormalizeInputEventName.
// To make things simpler just get rid of the parts we change in the event names we use here.
// This is a lot easier than trying to denormalize because there would be multiple possible
// denormalized forms for a single input.
NSString *RCTNormalizeAnimatedEventName(NSString *eventName)
{
if ([eventName hasPrefix:@"on"]) {
return [eventName substringFromIndex:2];
}
if ([eventName hasPrefix:@"top"]) {
return [eventName substringFromIndex:3];
}
return eventName;
}
@implementation RCTNativeAnimatedNodesManager
{
__weak RCTBridge *_bridge;
@ -321,7 +336,7 @@
RCTEventAnimation *driver =
[[RCTEventAnimation alloc] initWithEventPath:eventPath valueNode:(RCTValueAnimatedNode *)node];
NSString *key = [NSString stringWithFormat:@"%@%@", viewTag, eventName];
NSString *key = [NSString stringWithFormat:@"%@%@", viewTag, RCTNormalizeAnimatedEventName(eventName)];
if (_eventDrivers[key] != nil) {
[_eventDrivers[key] addObject:driver];
} else {
@ -335,7 +350,7 @@
eventName:(nonnull NSString *)eventName
animatedNodeTag:(nonnull NSNumber *)animatedNodeTag
{
NSString *key = [NSString stringWithFormat:@"%@%@", viewTag, eventName];
NSString *key = [NSString stringWithFormat:@"%@%@", viewTag, RCTNormalizeAnimatedEventName(eventName)];
if (_eventDrivers[key] != nil) {
if (_eventDrivers[key].count == 1) {
[_eventDrivers removeObjectForKey:key];
@ -357,7 +372,7 @@
return;
}
NSString *key = [NSString stringWithFormat:@"%@%@", event.viewTag, event.eventName];
NSString *key = [NSString stringWithFormat:@"%@%@", event.viewTag, RCTNormalizeAnimatedEventName(event.eventName)];
NSMutableArray<RCTEventAnimation *> *driversForKey = _eventDrivers[key];
if (driversForKey) {
for (RCTEventAnimation *driver in driversForKey) {

Просмотреть файл

@ -221,7 +221,7 @@ class InternalSettings extends React.Component<
class EventExample extends React.Component<{}, $FlowFixMeState> {
state = {
scrollX: new Animated.Value(0),
anim: new Animated.Value(0),
};
render() {
@ -233,7 +233,7 @@ class EventExample extends React.Component<{}, $FlowFixMeState> {
{
transform: [
{
rotate: this.state.scrollX.interpolate({
rotate: this.state.anim.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '1deg'],
}),
@ -246,7 +246,7 @@ class EventExample extends React.Component<{}, $FlowFixMeState> {
horizontal
style={{height: 100, marginTop: 16}}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this.state.scrollX}}}],
[{nativeEvent: {contentOffset: {x: this.state.anim}}}],
{useNativeDriver: true},
)}>
<View
@ -259,6 +259,13 @@ class EventExample extends React.Component<{}, $FlowFixMeState> {
<Text>Scroll me sideways!</Text>
</View>
</Animated.ScrollView>
<AnimatedSlider
maximumValue={200}
onValueChange={Animated.event(
[{nativeEvent: {value: this.state.anim}}],
{useNativeDriver: true},
)}
/>
</View>
);
}