mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-01-12 22:50:10 +08:00
More iOS animation fixes
Summary: Main change is to the property diffing - we now use the last known props set on the view rather than the default props to compute the diff. This requires exposing a `getProps` method on all view components which should be fine I think. I also realized that in more complex animations with multiple nodes, the node that the animation starts on might not be connected to a view, so we don't know if it's fabric just based on that, so we have to do a recursive search through the children to find if there are any that are associated with a fabric view to decide we should start the animation immediately. Unfortunately there can still be a timing gap here since the animated API is async and the uimanager API is sync - I'll need to change the animated API to be sync to completely fix this. Reviewed By: shergin Differential Revision: D14732028 fbshipit-source-id: 882c056b0b63aa576f8e42439be405cf7fb3147a
This commit is contained in:
committed by
Facebook Github Bot
parent
f04c039a98
commit
7b59c5a47e
@@ -23,6 +23,8 @@
|
||||
|
||||
@property (nonatomic, readonly) BOOL needsUpdate;
|
||||
|
||||
-(BOOL)isManagedByFabric;
|
||||
|
||||
/**
|
||||
* Marks a node and its children as needing update.
|
||||
*/
|
||||
|
||||
@@ -115,4 +115,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
// during the current update loop
|
||||
}
|
||||
|
||||
- (BOOL)isManagedByFabric
|
||||
{
|
||||
for (RCTAnimatedNode *child in _childNodes.objectEnumerator) {
|
||||
if ([child isManagedByFabric]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isManagedByFabric
|
||||
{
|
||||
return _managedByFabric;
|
||||
}
|
||||
|
||||
- (void)connectToView:(NSNumber *)viewTag
|
||||
viewName:(NSString *)viewName
|
||||
bridge:(RCTBridge *)bridge
|
||||
|
||||
@@ -19,7 +19,6 @@ typedef void (^AnimatedOperation)(RCTNativeAnimatedNodesManager *nodesManager);
|
||||
// Operations called before views have been updated.
|
||||
NSMutableArray<AnimatedOperation> *_preOperations;
|
||||
NSMutableDictionary<NSNumber *, NSNumber *> *_animIdIsManagedByFabric;
|
||||
NSMutableDictionary<NSNumber *, NSNumber *> *_animatedNodeIsManagedByFabric;
|
||||
}
|
||||
|
||||
RCT_EXPORT_MODULE();
|
||||
@@ -88,7 +87,7 @@ RCT_EXPORT_METHOD(startAnimatingNode:(nonnull NSNumber *)animationId
|
||||
[self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
|
||||
[nodesManager startAnimatingNode:animationId nodeTag:nodeTag config:config endCallback:callBack];
|
||||
}];
|
||||
if ([_animatedNodeIsManagedByFabric[nodeTag] boolValue]) {
|
||||
if ([_nodesManager isNodeManagedByFabric:nodeTag]) {
|
||||
_animIdIsManagedByFabric[animationId] = @YES;
|
||||
[self flushOperationQueues];
|
||||
}
|
||||
@@ -138,9 +137,6 @@ RCT_EXPORT_METHOD(connectAnimatedNodeToView:(nonnull NSNumber *)nodeTag
|
||||
viewTag:(nonnull NSNumber *)viewTag)
|
||||
{
|
||||
NSString *viewName = [self.bridge.uiManager viewNameForReactTag:viewTag];
|
||||
if (RCTUIManagerTypeForTagIsFabric(nodeTag)) {
|
||||
_animatedNodeIsManagedByFabric[nodeTag] = @YES;
|
||||
}
|
||||
[self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
|
||||
[nodesManager connectAnimatedNodeToView:nodeTag viewTag:viewTag viewName:viewName];
|
||||
}];
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
- (void)stepAnimations:(nonnull CADisplayLink *)displaylink;
|
||||
|
||||
- (BOOL)isNodeManagedByFabric:(nonnull NSNumber *)tag;
|
||||
|
||||
// graph
|
||||
|
||||
- (void)createAnimatedNode:(nonnull NSNumber *)tag
|
||||
|
||||
@@ -50,6 +50,12 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isNodeManagedByFabric:(nonnull NSNumber *)tag
|
||||
{
|
||||
RCTAnimatedNode *node = _animationNodes[tag];
|
||||
return [node isManagedByFabric];
|
||||
}
|
||||
|
||||
#pragma mark -- Graph
|
||||
|
||||
- (void)createAnimatedNode:(nonnull NSNumber *)tag
|
||||
|
||||
@@ -29,10 +29,14 @@ using namespace facebook::react;
|
||||
static const auto defaultProps = std::make_shared<const ViewProps>();
|
||||
_props = defaultProps;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (facebook::react::SharedProps)props
|
||||
{
|
||||
return _props;
|
||||
}
|
||||
|
||||
- (void)setContentView:(UIView *)contentView
|
||||
{
|
||||
if (_contentView) {
|
||||
|
||||
@@ -85,6 +85,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (void)prepareForRecycle;
|
||||
|
||||
/**
|
||||
* Read the last props used to update the view.
|
||||
*/
|
||||
- (facebook::react::SharedProps)props;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#import <React/RCTMountingManagerDelegate.h>
|
||||
#import <React/RCTPrimitives.h>
|
||||
#import <react/core/ComponentDescriptor.h>
|
||||
#import <react/core/ReactPrimitives.h>
|
||||
#import <react/mounting/ShadowView.h>
|
||||
#import <react/mounting/ShadowViewMutation.h>
|
||||
@@ -40,8 +41,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)optimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;
|
||||
|
||||
- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
|
||||
oldProps:(facebook::react::SharedProps)oldProps
|
||||
newProps:(facebook::react::SharedProps)newProps;
|
||||
changedProps:(NSDictionary *)props
|
||||
componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
#import "RCTMountingManager.h"
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTFollyConvert.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <react/core/LayoutableShadowNode.h>
|
||||
#import <react/core/RawProps.h>
|
||||
#import <react/debug/SystraceSection.h>
|
||||
|
||||
#import "RCTComponentViewProtocol.h"
|
||||
@@ -40,7 +42,7 @@ using namespace facebook::react;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList)mutations rootTag:(ReactTag)rootTag
|
||||
- (void)performTransactionWithMutations:(ShadowViewMutationList)mutations rootTag:(ReactTag)rootTag
|
||||
{
|
||||
NSMutableArray<RCTMountItemProtocol> *mountItems;
|
||||
|
||||
@@ -193,9 +195,12 @@ using namespace facebook::react;
|
||||
}
|
||||
|
||||
- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
|
||||
oldProps:(SharedProps)oldProps
|
||||
newProps:(SharedProps)newProps
|
||||
changedProps:(NSDictionary *)props
|
||||
componentDescriptor:(const ComponentDescriptor &)componentDescriptor
|
||||
{
|
||||
UIView<RCTComponentViewProtocol> *componentView = [self->_componentViewRegistry componentViewByTag:reactTag];
|
||||
SharedProps oldProps = [componentView props];
|
||||
SharedProps newProps = componentDescriptor.cloneProps(oldProps, RawProps(convertIdToFollyDynamic(props)));
|
||||
RCTUpdatePropsMountItem *mountItem = [[RCTUpdatePropsMountItem alloc] initWithTag:reactTag
|
||||
oldProps:oldProps
|
||||
newProps:newProps];
|
||||
|
||||
@@ -34,6 +34,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)prepareForRecycle;
|
||||
|
||||
- (facebook::react::SharedProps)props;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -87,4 +87,10 @@ using namespace facebook::react;
|
||||
// Default implementation does nothing.
|
||||
}
|
||||
|
||||
- (facebook::react::SharedProps)props
|
||||
{
|
||||
RCTAssert(NO, @"props access should be implemented by RCTViewComponentView.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -74,7 +74,7 @@ using namespace facebook::react;
|
||||
} else {
|
||||
_reactNativeConfig = std::make_shared<const EmptyReactNativeConfig>();
|
||||
}
|
||||
|
||||
|
||||
_observers = [NSMutableArray array];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
@@ -176,17 +176,9 @@ using namespace facebook::react;
|
||||
}
|
||||
ComponentHandle handle = [[componentView class] componentHandle];
|
||||
const facebook::react::ComponentDescriptor &componentDescriptor = [self._scheduler getComponentDescriptor:handle];
|
||||
|
||||
// Note: we use an empty object for `oldProps` to rely on the diffing algorithm internal to the
|
||||
// RCTComponentViewProtocol::updateProps method. If there is a bug in that diffing, some props
|
||||
// could get reset. One way around this would be to require all RCTComponentViewProtocol
|
||||
// implementations to expose their current props so we could clone them, but that could be
|
||||
// problematic for threading and other reasons.
|
||||
facebook::react::SharedProps newProps =
|
||||
componentDescriptor.cloneProps(nullptr, RawProps(convertIdToFollyDynamic(props)));
|
||||
facebook::react::SharedProps oldProps = componentDescriptor.cloneProps(nullptr, RawProps(folly::dynamic::object()));
|
||||
|
||||
[self->_mountingManager synchronouslyUpdateViewOnUIThread:tag oldProps:oldProps newProps:newProps];
|
||||
[self->_mountingManager synchronouslyUpdateViewOnUIThread:tag
|
||||
changedProps:props
|
||||
componentDescriptor:componentDescriptor];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -225,7 +217,7 @@ using namespace facebook::react;
|
||||
// Make sure initializeBridge completed
|
||||
messageQueueThread->runOnQueueSync([] {});
|
||||
}
|
||||
|
||||
|
||||
auto runtime = (facebook::jsi::Runtime *)((RCTCxxBridge *)_batchedBridge).runtime;
|
||||
|
||||
RuntimeExecutor runtimeExecutor =
|
||||
|
||||
Reference in New Issue
Block a user