Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offload NavigatorExperimental transition animations #10289

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Examples/UIExplorer/js/NativeAnimationsExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ class EventExample extends React.Component {
<Animated.ScrollView
horizontal
style={{ height: 100, marginTop: 16 }}
scrollEventThrottle={16}
onScroll={
Animated.event([{
nativeEvent: { contentOffset: { x: this.state.scrollX } }
Expand Down Expand Up @@ -462,19 +463,18 @@ exports.examples = [
},
},
{
title: 'Internal Settings',
title: 'Animated events',
render: function() {
return (
<InternalSettings />
<EventExample />
);
},
},
{
title: 'Animated events',
platform: 'android',
title: 'Internal Settings',
render: function() {
return (
<EventExample />
<InternalSettings />
);
},
},
Expand Down
10 changes: 8 additions & 2 deletions Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
13E501CC1D07A644005F35D8 /* RCTAnimationUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */; };
13E501CF1D07A644005F35D8 /* RCTNativeAnimatedModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501BE1D07A644005F35D8 /* RCTNativeAnimatedModule.m */; };
13E501D41D07A644005F35D8 /* RCTViewPropertyMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501C81D07A644005F35D8 /* RCTViewPropertyMapper.m */; };
13E501E81D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */; };
13E501E91D07A6C9005F35D8 /* RCTAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */; };
13E501EA1D07A6C9005F35D8 /* RCTAnimationDriverNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */; };
13E501EB1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */; };
Expand All @@ -20,6 +19,8 @@
13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; };
13E501F01D07A6C9005F35D8 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; };
193F64F41D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */; };
195140411D6FD650003D5882 /* RCTEventAnimationDriver.m in Sources */ = {isa = PBXBuildFile; fileRef = 195140401D6FD650003D5882 /* RCTEventAnimationDriver.m */; };
284F37831DA8249100E93C9D /* RCTAdditionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */; };
2D3B5EF21D9B0B3100451313 /* RCTAnimationUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */; };
2D3B5EF31D9B0B3400451313 /* RCTViewPropertyMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501C81D07A644005F35D8 /* RCTViewPropertyMapper.m */; };
2D3B5EF41D9B0B3700451313 /* RCTNativeAnimatedModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501BE1D07A644005F35D8 /* RCTNativeAnimatedModule.m */; };
Expand Down Expand Up @@ -88,6 +89,8 @@
13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTValueAnimatedNode.m; sourceTree = "<group>"; };
193F64F21D776EC6004D1CAA /* RCTDiffClampAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDiffClampAnimatedNode.h; sourceTree = "<group>"; };
193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDiffClampAnimatedNode.m; sourceTree = "<group>"; };
1951403F1D6FD650003D5882 /* RCTEventAnimationDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTEventAnimationDriver.h; sourceTree = "<group>"; };
195140401D6FD650003D5882 /* RCTEventAnimationDriver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventAnimationDriver.m; sourceTree = "<group>"; };
2D2A28201D9B03D100D4039D /* libRCTAnimation-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTAnimation-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDivisionAnimatedNode.h; sourceTree = "<group>"; };
5C9894941D999639008027DB /* RCTDivisionAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDivisionAnimatedNode.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -155,6 +158,8 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
1951403F1D6FD650003D5882 /* RCTEventAnimationDriver.h */,
195140401D6FD650003D5882 /* RCTEventAnimationDriver.m */,
13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */,
13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */,
13E501C71D07A644005F35D8 /* RCTViewPropertyMapper.h */,
Expand Down Expand Up @@ -267,6 +272,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
284F37831DA8249100E93C9D /* RCTAdditionAnimatedNode.m in Sources */,
13E501F01D07A6C9005F35D8 /* RCTValueAnimatedNode.m in Sources */,
94DAE3F91D7334A70059942F /* RCTModuloAnimatedNode.m in Sources */,
193F64F41D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m in Sources */,
Expand All @@ -277,8 +283,8 @@
13E501ED1D07A6C9005F35D8 /* RCTPropsAnimatedNode.m in Sources */,
13E501E91D07A6C9005F35D8 /* RCTAnimatedNode.m in Sources */,
13E501EB1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m in Sources */,
13E501E81D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m in Sources */,
5C9894951D999639008027DB /* RCTDivisionAnimatedNode.m in Sources */,
195140411D6FD650003D5882 /* RCTEventAnimationDriver.m in Sources */,
13E501EA1D07A6C9005F35D8 /* RCTAnimationDriverNode.m in Sources */,
13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */,
13E501D41D07A644005F35D8 /* RCTViewPropertyMapper.m in Sources */,
Expand Down
24 changes: 24 additions & 0 deletions Libraries/NativeAnimation/RCTEventAnimationDriver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import <Foundation/Foundation.h>

#import "RCTValueAnimatedNode.h"
#import "RCTEventDispatcher.h"

@interface RCTEventAnimationDriver : NSObject

@property (nonatomic, readonly, weak) RCTValueAnimatedNode *valueNode;

- (instancetype)initWithEventPath:(NSArray<NSString *> *)eventPath
valueNode:(RCTValueAnimatedNode *)valueNode;

- (void) updateWithEvent:(id<RCTEvent>)event;

@end
40 changes: 40 additions & 0 deletions Libraries/NativeAnimation/RCTEventAnimationDriver.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "RCTEventAnimationDriver.h"

@implementation RCTEventAnimationDriver
{
NSArray<NSString *> *_eventPath;
}

- (instancetype)initWithEventPath:(NSArray<NSString *> *)eventPath
valueNode:(RCTValueAnimatedNode *)valueNode
{
if ((self = [super init])) {
_eventPath = eventPath;
_valueNode = valueNode;
}
return self;
}

- (void) updateWithEvent:(id<RCTEvent>)event
{
NSArray *args = [event arguments];
// Supported events args are in the following order: viewTag, eventName, eventData.
id curValue = args[2];
for (NSString *key in _eventPath) {
curValue = [curValue valueForKey:key];
}

_valueNode.value = ((NSNumber *)curValue).doubleValue;
[_valueNode setNeedsUpdate];
}

@end
3 changes: 2 additions & 1 deletion Libraries/NativeAnimation/RCTNativeAnimatedModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
#import "RCTBridgeModule.h"
#import "RCTValueAnimatedNode.h"
#import "RCTEventEmitter.h"
#import "RCTEventDispatcher.h"

@interface RCTNativeAnimatedModule : RCTEventEmitter <RCTBridgeModule, RCTValueAnimatedNodeObserver>
@interface RCTNativeAnimatedModule : RCTEventEmitter <RCTBridgeModule, RCTValueAnimatedNodeObserver, RCTEventDispatcherObserver>

@end
87 changes: 79 additions & 8 deletions Libraries/NativeAnimation/RCTNativeAnimatedModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import "RCTAnimationUtils.h"
#import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTEventAnimationDriver.h"
#import "RCTInterpolationAnimatedNode.h"
#import "RCTLog.h"
#import "RCTDiffClampAnimatedNode.h"
Expand All @@ -28,6 +29,7 @@ @implementation RCTNativeAnimatedModule
{
NSMutableDictionary<NSNumber *, RCTAnimatedNode *> *_animationNodes;
NSMutableDictionary<NSNumber *, RCTAnimationDriverNode *> *_animationDrivers;
NSMutableDictionary<NSString *, RCTEventAnimationDriver *> *_eventAnimationDrivers;
NSMutableSet<RCTAnimationDriverNode *> *_activeAnimations;
NSMutableSet<RCTAnimationDriverNode *> *_finishedAnimations;
NSMutableSet<RCTValueAnimatedNode *> *_updatedValueNodes;
Expand All @@ -43,10 +45,18 @@ - (void)setBridge:(RCTBridge *)bridge

_animationNodes = [NSMutableDictionary new];
_animationDrivers = [NSMutableDictionary new];
_eventAnimationDrivers = [NSMutableDictionary new];
_activeAnimations = [NSMutableSet new];
_finishedAnimations = [NSMutableSet new];
_updatedValueNodes = [NSMutableSet new];
_propAnimationNodes = [NSMutableSet new];

[bridge.eventDispatcher addDispatchObserver:self];
}

- (void)dealloc
{
[self.bridge.eventDispatcher removeDispatchObserver:self];
}


Expand Down Expand Up @@ -150,7 +160,7 @@ - (dispatch_queue_t)methodQueue
[_activeAnimations addObject:animationDriver];
_animationDrivers[animationId] = animationDriver;
[animationDriver startAnimation];
[self startAnimation];
[self startAnimationLoopIfNeeded];
}

RCT_EXPORT_METHOD(stopAnimation:(nonnull NSNumber *)animationId)
Expand Down Expand Up @@ -251,23 +261,87 @@ - (dispatch_queue_t)methodQueue
}
}

RCT_EXPORT_METHOD(addAnimatedEventToView:(nonnull NSNumber *)viewTag
eventName:(nonnull NSString *)eventName
eventMapping:(NSDictionary<NSString *, id> *)eventMapping)
{
NSNumber *nodeTag = [RCTConvert NSNumber:eventMapping[@"animatedValueTag"]];
RCTAnimatedNode *node = _animationNodes[nodeTag];

if (!node) {
RCTLogError(@"Animated node with tag %@ does not exists", nodeTag);
return;
}

if (![node isKindOfClass:[RCTValueAnimatedNode class]]) {
RCTLogError(@"Animated node connected to event should be of type RCTValueAnimatedNode");
return;
}

NSArray<NSString *> *eventPath = [RCTConvert NSStringArray:eventMapping[@"nativeEventPath"]];

RCTEventAnimationDriver *driver =
[[RCTEventAnimationDriver alloc] initWithEventPath:eventPath valueNode:(RCTValueAnimatedNode *)node];

[_eventAnimationDrivers setObject:driver forKey:[NSString stringWithFormat:@"%@%@", viewTag, eventName]];
}

RCT_EXPORT_METHOD(removeAnimatedEventFromView:(nonnull NSNumber *)viewTag
eventName:(nonnull NSString *)eventName)
{
[_eventAnimationDrivers removeObjectForKey:[NSString stringWithFormat:@"%@%@", viewTag, eventName]];
}

- (void)animatedNode:(RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value
{
[self sendEventWithName:@"onAnimatedValueUpdate"
body:@{@"tag": node.nodeTag, @"value": @(value)}];
}

- (BOOL)eventDispatcherWillDispatchEvent:(id<RCTEvent>)event
{
// Native animated events only work for events dispatched from the main queue.
if (!RCTIsMainQueue() || [_eventAnimationDrivers count] == 0) {
return NO;
}

NSString *key = [NSString stringWithFormat:@"%@%@", [event viewTag], [event eventName]];
RCTEventAnimationDriver *driver = [_eventAnimationDrivers valueForKey:key];

if (driver) {
[driver updateWithEvent:event];

for (RCTPropsAnimatedNode *propsNode in _propAnimationNodes) {
[propsNode updateNodeIfNecessary];
}

[driver.valueNode cleanupAnimationUpdate];

return YES;
}

return NO;
}


#pragma mark -- Animation Loop

- (void)startAnimation
- (void)startAnimationLoopIfNeeded
{
if (!_displayLink && _activeAnimations.count > 0) {
if (!_displayLink && (_activeAnimations.count > 0 || _updatedValueNodes.count > 0)) {
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateAnimations)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
}

- (void)stopAnimationLoopIfNeeded
{
if (_displayLink && _activeAnimations.count == 0 && _updatedValueNodes.count == 0) {
[_displayLink invalidate];
_displayLink = nil;
}
}

- (void)updateAnimations
{
// Step Current active animations
Expand Down Expand Up @@ -302,11 +376,8 @@ - (void)updateAnimations
[_animationDrivers removeObjectForKey:driverNode.animationId];
}
[_finishedAnimations removeAllObjects];

if (_activeAnimations.count == 0) {
[_displayLink invalidate];
_displayLink = nil;
}

[self stopAnimationLoopIfNeeded];
}

@end
11 changes: 9 additions & 2 deletions Libraries/NavigationExperimental/NavigationTransitioner.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const DefaultTransitionSpec = {
duration: 250,
easing: Easing.inOut(Easing.ease),
timing: Animated.timing,
useNativeDriver: true,
};

class NavigationTransitioner extends React.Component<any, Props, State> {
Expand Down Expand Up @@ -198,8 +199,14 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
isMeasured: true,
};

layout.height.setValue(height);
layout.width.setValue(width);
Animated.event([{
nativeEvent: {
layout: {
height: layout.height,
width: layout.width,
},
},
}]);

const nextState = {
...this.state,
Expand Down
24 changes: 24 additions & 0 deletions React/Base/RCTEventDispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);

@end

/**
* This protocol allows observing events dispatched by RCTEventDispatcher.
*/
@protocol RCTEventDispatcherObserver <NSObject>

/**
* Called before dispatching an event, on the same thread the event was
* dispatched from. Return YES if the event was handled and must not be
* sent to JS.
*/
- (BOOL)eventDispatcherWillDispatchEvent:(id<RCTEvent>)event;

@end


/**
* This class wraps the -[RCTBridge enqueueJSCall:args:] method, and
Expand Down Expand Up @@ -93,6 +107,16 @@ __deprecated_msg("Use RCTDirectEventBlock or RCTBubblingEventBlock instead");
*/
- (void)sendEvent:(id<RCTEvent>)event;

/**
* Add an event dispatcher observer.
*/
- (void)addDispatchObserver:(id<RCTEventDispatcherObserver>)observer;

/**
* Remove an event dispatcher observer.
*/
- (void)removeDispatchObserver:(id<RCTEventDispatcherObserver>)observer;

@end

@interface RCTBridge (RCTEventDispatcher)
Expand Down
Loading