mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: `RCTPropsAnimatedNode` uses the bridge to access it's current surface presenter to perform animations. In bridgeless mode, the surface presenter is not owned by the bridge. Instead, pass the surface presenter through the ownership chain: `RCTNativeAnimated*Module` -> `RCTNativeAnimatedNodesManager` -> `RCTPropsAnimatedNode` `RCTSurfacePresenter` should not be strongly held by any of these animation internals. If it gets destroyed at a higher level, animations should not be completed. Changelog: [Internal] Differential Revision: D23272735 fbshipit-source-id: ce08ee3b59ac2ba70e31cebb7ba8e9f3a644c848
144 lines
4.1 KiB
Objective-C
144 lines
4.1 KiB
Objective-C
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import "RCTPropsAnimatedNode.h"
|
|
|
|
#import <React/RCTAnimationUtils.h>
|
|
#import <React/RCTLog.h>
|
|
#import <React/RCTStyleAnimatedNode.h>
|
|
#import <React/RCTUIManager.h>
|
|
#import <React/RCTValueAnimatedNode.h>
|
|
|
|
@implementation RCTPropsAnimatedNode
|
|
{
|
|
NSNumber *_connectedViewTag;
|
|
NSNumber *_rootTag;
|
|
NSString *_connectedViewName;
|
|
__weak RCTBridge *_bridge;
|
|
__weak id<RCTSurfacePresenterStub> _surfacePresenter;
|
|
NSMutableDictionary<NSString *, NSObject *> *_propsDictionary; // TODO: use RawProps or folly::dynamic directly
|
|
BOOL _managedByFabric;
|
|
}
|
|
|
|
- (instancetype)initWithTag:(NSNumber *)tag
|
|
config:(NSDictionary<NSString *, id> *)config
|
|
{
|
|
if (self = [super initWithTag:tag config:config]) {
|
|
_propsDictionary = [NSMutableDictionary new];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)isManagedByFabric
|
|
{
|
|
return _managedByFabric;
|
|
}
|
|
|
|
- (void)connectToView:(NSNumber *)viewTag
|
|
viewName:(NSString *)viewName
|
|
bridge:(RCTBridge *)bridge
|
|
surfacePresenter:(id<RCTSurfacePresenterStub> )surfacePresenter
|
|
{
|
|
_bridge = bridge;
|
|
_surfacePresenter = surfacePresenter;
|
|
_connectedViewTag = viewTag;
|
|
_connectedViewName = viewName;
|
|
_managedByFabric = RCTUIManagerTypeForTagIsFabric(viewTag);
|
|
_rootTag = nil;
|
|
}
|
|
|
|
- (void)disconnectFromView:(NSNumber *)viewTag
|
|
{
|
|
_bridge = nil;
|
|
_surfacePresenter = nil;
|
|
_connectedViewTag = nil;
|
|
_connectedViewName = nil;
|
|
_managedByFabric = NO;
|
|
_rootTag = nil;
|
|
}
|
|
|
|
- (void)updateView
|
|
{
|
|
if (_managedByFabric) {
|
|
if (_bridge.surfacePresenter) {
|
|
[_bridge.surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag
|
|
props:_propsDictionary];
|
|
} else {
|
|
[_surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag
|
|
props:_propsDictionary];
|
|
}
|
|
} else {
|
|
[_bridge.uiManager synchronouslyUpdateViewOnUIThread:_connectedViewTag
|
|
viewName:_connectedViewName
|
|
props:_propsDictionary];
|
|
}
|
|
}
|
|
|
|
- (void)restoreDefaultValues
|
|
{
|
|
if (_managedByFabric) {
|
|
// Restoring to default values causes render of inconsistent state
|
|
// to the user because it isn't synchonised with Fabric's UIManager.
|
|
return;
|
|
}
|
|
// Restore the default value for all props that were modified by this node.
|
|
for (NSString *key in _propsDictionary.allKeys) {
|
|
_propsDictionary[key] = [NSNull null];
|
|
}
|
|
|
|
if (_propsDictionary.count) {
|
|
[self updateView];
|
|
}
|
|
}
|
|
|
|
- (NSString *)propertyNameForParentTag:(NSNumber *)parentTag
|
|
{
|
|
__block NSString *propertyName;
|
|
[self.config[@"props"] enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull property, NSNumber *_Nonnull tag, BOOL *_Nonnull stop) {
|
|
if ([tag isEqualToNumber:parentTag]) {
|
|
propertyName = property;
|
|
*stop = YES;
|
|
}
|
|
}];
|
|
return propertyName;
|
|
}
|
|
|
|
- (void)performUpdate
|
|
{
|
|
[super performUpdate];
|
|
|
|
// Since we are updating nodes after detaching them from views there is a time where it's
|
|
// possible that the view was disconnected and still receive an update, this is normal and we can
|
|
// simply skip that update.
|
|
if (!_connectedViewTag) {
|
|
return;
|
|
}
|
|
|
|
for (NSNumber *parentTag in self.parentNodes.keyEnumerator) {
|
|
RCTAnimatedNode *parentNode = [self.parentNodes objectForKey:parentTag];
|
|
if ([parentNode isKindOfClass:[RCTStyleAnimatedNode class]]) {
|
|
[self->_propsDictionary addEntriesFromDictionary:[(RCTStyleAnimatedNode *)parentNode propsDictionary]];
|
|
|
|
} else if ([parentNode isKindOfClass:[RCTValueAnimatedNode class]]) {
|
|
NSString *property = [self propertyNameForParentTag:parentTag];
|
|
id animatedObject = [(RCTValueAnimatedNode *)parentNode animatedObject];
|
|
if (animatedObject) {
|
|
self->_propsDictionary[property] = animatedObject;
|
|
} else {
|
|
CGFloat value = [(RCTValueAnimatedNode *)parentNode value];
|
|
self->_propsDictionary[property] = @(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_propsDictionary.count) {
|
|
[self updateView];
|
|
}
|
|
}
|
|
|
|
@end
|