mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add support for native animated events on iOS
Summary: This adds native support for `Animated.event` on iOS. **Test plan** Tested in the native animated UIExplorer example that it works properly like on Android. Closes https://github.com/facebook/react-native/pull/9598 Differential Revision: D4110331 fbshipit-source-id: 15748d23d0f475f2bcd1040ca3dca33e2620f058
This commit is contained in:
committed by
Facebook Github Bot
parent
0fe1c7a9ff
commit
fc11a5fde8
@@ -15,6 +15,7 @@
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventAnimation.h"
|
||||
#import "RCTInterpolationAnimatedNode.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTDiffClampAnimatedNode.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
{
|
||||
NSMutableDictionary<NSNumber *, RCTAnimatedNode *> *_animationNodes;
|
||||
NSMutableDictionary<NSNumber *, id<RCTAnimationDriver>> *_animationDrivers;
|
||||
NSMutableDictionary<NSString *, RCTEventAnimation *> *_eventAnimationDrivers;
|
||||
NSMutableSet<id<RCTAnimationDriver>> *_activeAnimations;
|
||||
NSMutableSet<id<RCTAnimationDriver>> *_finishedAnimations;
|
||||
NSMutableSet<RCTValueAnimatedNode *> *_updatedValueNodes;
|
||||
@@ -45,10 +47,18 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
_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];
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +167,7 @@ RCT_EXPORT_METHOD(startAnimatingNode:(nonnull NSNumber *)animationId
|
||||
[_activeAnimations addObject:animationDriver];
|
||||
_animationDrivers[animationId] = animationDriver;
|
||||
[animationDriver startAnimation];
|
||||
[self startAnimation];
|
||||
[self startAnimationLoopIfNeeded];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(stopAnimation:(nonnull NSNumber *)animationId)
|
||||
@@ -263,12 +273,64 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
||||
}
|
||||
}
|
||||
|
||||
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"]];
|
||||
|
||||
RCTEventAnimation *driver =
|
||||
[[RCTEventAnimation alloc] initWithEventPath:eventPath valueNode:(RCTValueAnimatedNode *)node];
|
||||
|
||||
_eventAnimationDrivers[[NSString stringWithFormat:@"%@%@", viewTag, eventName]] = driver;
|
||||
}
|
||||
|
||||
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];
|
||||
RCTEventAnimation *driver = _eventAnimationDrivers[key];
|
||||
|
||||
if (driver) {
|
||||
[driver updateWithEvent:event];
|
||||
[self updateViewsProps];
|
||||
[driver.valueNode cleanupAnimationUpdate];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)updateViewsProps
|
||||
{
|
||||
for (RCTPropsAnimatedNode *propsNode in _propAnimationNodes) {
|
||||
@@ -278,14 +340,22 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
||||
|
||||
#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
|
||||
@@ -321,10 +391,7 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
||||
}
|
||||
[_finishedAnimations removeAllObjects];
|
||||
|
||||
if (_activeAnimations.count == 0) {
|
||||
[_displayLink invalidate];
|
||||
_displayLink = nil;
|
||||
}
|
||||
[self stopAnimationLoopIfNeeded];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user