Skip to content

Commit 0e204e1

Browse files
janicduplessisFacebook Github Bot 6
authored andcommitted
Add support for value listener
Summary: Adds support for `Animated.Value#addListener` for native driven animated values. Same as #8844 but for iOS. This depends on some JS code in #8844 so only review the 2nd commit and let's wait for #8844 to land first. **Test plan** Tested using the UIExplorer example. Closes #9194 Differential Revision: D3681749 fbshipit-source-id: 521a61e2221c1ad1f6f40c75dd2dc957361d0271
1 parent 68d483e commit 0e204e1

File tree

7 files changed

+72
-25
lines changed

7 files changed

+72
-25
lines changed

Examples/UIExplorer/js/NativeAnimationsExample.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,6 @@ exports.examples = [
347347
},
348348
{
349349
title: 'Animated value listener',
350-
platform: 'android',
351350
render: function() {
352351
return (
353352
<ValueListenerExample />

Libraries/Animated/src/AnimatedImplementation.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
*/
1212
'use strict';
1313

14-
var DeviceEventEmitter = require('RCTDeviceEventEmitter');
1514
var InteractionManager = require('InteractionManager');
1615
var Interpolation = require('Interpolation');
1716
var React = require('React');
@@ -750,13 +749,12 @@ class AnimatedValue extends AnimatedWithChildren {
750749
}
751750

752751
_startListeningToNativeValueUpdates() {
753-
if (this.__nativeAnimatedValueListener ||
754-
!NativeAnimatedHelper.supportsNativeListener()) {
752+
if (this.__nativeAnimatedValueListener) {
755753
return;
756754
}
757755

758756
NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
759-
this.__nativeAnimatedValueListener = DeviceEventEmitter.addListener(
757+
this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener(
760758
'onAnimatedValueUpdate',
761759
(data) => {
762760
if (data.tag !== this.__getNativeTag()) {
@@ -768,8 +766,7 @@ class AnimatedValue extends AnimatedWithChildren {
768766
}
769767

770768
_stopListeningForNativeValueUpdates() {
771-
if (!this.__nativeAnimatedValueListener ||
772-
!NativeAnimatedHelper.supportsNativeListener()) {
769+
if (!this.__nativeAnimatedValueListener) {
773770
return;
774771
}
775772

Libraries/Animated/src/NativeAnimatedHelper.js

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,24 @@
1111
*/
1212
'use strict';
1313

14-
var NativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
14+
const NativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
15+
const NativeEventEmitter = require('NativeEventEmitter');
1516

16-
var invariant = require('fbjs/lib/invariant');
17+
const invariant = require('fbjs/lib/invariant');
1718

18-
var __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */
19-
var __nativeAnimationIdCount = 1; /* used for started animations */
19+
let __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */
20+
let __nativeAnimationIdCount = 1; /* used for started animations */
2021

2122
type EndResult = {finished: bool};
2223
type EndCallback = (result: EndResult) => void;
2324

25+
let nativeEventEmitter;
26+
2427
/**
25-
* Simple wrappers around NativeANimatedModule to provide flow and autocmplete support for
28+
* Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for
2629
* the native module methods
2730
*/
28-
var API = {
31+
const API = {
2932
createAnimatedNode: function(tag: number, config: Object): void {
3033
assertNativeAnimatedModule();
3134
NativeAnimatedModule.createAnimatedNode(tag, config);
@@ -79,7 +82,7 @@ var API = {
7982
* to be updated through the shadow view hierarchy (all non-layout properties). This list is limited
8083
* to the properties that will perform best when animated off the JS thread.
8184
*/
82-
var PROPS_WHITELIST = {
85+
const PROPS_WHITELIST = {
8386
style: {
8487
opacity: true,
8588
transform: true,
@@ -91,7 +94,7 @@ var PROPS_WHITELIST = {
9194
},
9295
};
9396

94-
var TRANSFORM_WHITELIST = {
97+
const TRANSFORM_WHITELIST = {
9598
translateX: true,
9699
translateY: true,
97100
scale: true,
@@ -152,11 +155,6 @@ function assertNativeAnimatedModule(): void {
152155
invariant(NativeAnimatedModule, 'Native animated module is not available');
153156
}
154157

155-
// TODO: remove this when iOS supports native listeners.
156-
function supportsNativeListener(): bool {
157-
return !!NativeAnimatedModule.startListeningToAnimatedNodeValue;
158-
}
159-
160158
module.exports = {
161159
API,
162160
validateProps,
@@ -166,5 +164,10 @@ module.exports = {
166164
generateNewNodeTag,
167165
generateNewAnimationId,
168166
assertNativeAnimatedModule,
169-
supportsNativeListener,
167+
get nativeEventEmitter() {
168+
if (!nativeEventEmitter) {
169+
nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule);
170+
}
171+
return nativeEventEmitter;
172+
},
170173
};

Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,17 @@
1010
#import "RCTAnimatedNode.h"
1111
#import <UIKit/UIKit.h>
1212

13+
@class RCTValueAnimatedNode;
14+
15+
@protocol RCTValueAnimatedNodeObserver <NSObject>
16+
17+
- (void)animatedNode:(RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value;
18+
19+
@end
20+
1321
@interface RCTValueAnimatedNode : RCTAnimatedNode
1422

1523
@property (nonatomic, assign) CGFloat value;
24+
@property (nonatomic, weak) id<RCTValueAnimatedNodeObserver> valueObserver;
1625

1726
@end

Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,13 @@
1111

1212
@implementation RCTValueAnimatedNode
1313

14+
- (void)setValue:(CGFloat)value
15+
{
16+
_value = value;
17+
18+
if (_valueObserver) {
19+
[_valueObserver animatedNode:self didUpdateValue:_value];
20+
}
21+
}
22+
1423
@end

Libraries/NativeAnimation/RCTNativeAnimatedModule.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99
#import "RCTBridgeModule.h"
10+
#import "RCTValueAnimatedNode.h"
11+
#import "RCTEventEmitter.h"
1012

11-
@interface RCTNativeAnimatedModule : NSObject <RCTBridgeModule>
13+
@interface RCTNativeAnimatedModule : RCTEventEmitter <RCTBridgeModule, RCTValueAnimatedNodeObserver>
1214

1315
@end

Libraries/NativeAnimation/RCTNativeAnimatedModule.m

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,12 @@ @implementation RCTNativeAnimatedModule
3232
CADisplayLink *_displayLink;
3333
}
3434

35-
@synthesize bridge = _bridge;
36-
3735
RCT_EXPORT_MODULE()
3836

3937
- (void)setBridge:(RCTBridge *)bridge
4038
{
41-
_bridge = bridge;
39+
[super setBridge:bridge];
40+
4241
_animationNodes = [NSMutableDictionary new];
4342
_animationDrivers = [NSMutableDictionary new];
4443
_activeAnimations = [NSMutableSet new];
@@ -47,11 +46,17 @@ - (void)setBridge:(RCTBridge *)bridge
4746
_propAnimationNodes = [NSMutableSet new];
4847
}
4948

49+
5050
- (dispatch_queue_t)methodQueue
5151
{
5252
return dispatch_get_main_queue();
5353
}
5454

55+
- (NSArray<NSString *> *)supportedEvents
56+
{
57+
return @[@"onAnimatedValueUpdate"];
58+
}
59+
5560
RCT_EXPORT_METHOD(createAnimatedNode:(nonnull NSNumber *)tag
5661
config:(NSDictionary<NSString *, id> *)config)
5762
{
@@ -198,6 +203,29 @@ - (dispatch_queue_t)methodQueue
198203
}
199204
}
200205

206+
RCT_EXPORT_METHOD(startListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
207+
{
208+
RCTAnimatedNode *node = _animationNodes[tag];
209+
if (node && [node isKindOfClass:[RCTValueAnimatedNode class]]) {
210+
((RCTValueAnimatedNode *)node).valueObserver = self;
211+
}
212+
}
213+
214+
RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
215+
{
216+
RCTAnimatedNode *node = _animationNodes[tag];
217+
if (node && [node isKindOfClass:[RCTValueAnimatedNode class]]) {
218+
((RCTValueAnimatedNode *)node).valueObserver = nil;
219+
}
220+
}
221+
222+
- (void)animatedNode:(RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value
223+
{
224+
[self sendEventWithName:@"onAnimatedValueUpdate"
225+
body:@{@"tag": node.nodeTag, @"value": @(value)}];
226+
}
227+
228+
201229
#pragma mark -- Animation Loop
202230

203231
- (void)startAnimation

0 commit comments

Comments
 (0)