Revert "Reverted commit D3417194"

Summary:
This reverts commit 7df2af58c78d57d95dc1577e489dc795bafe7ce8.

cc janicduplessis
Closes https://github.com/facebook/react-native/pull/8049

Differential Revision: D3417557

fbshipit-source-id: 3853b06e91a2aae441835807f73fb78e6ef79344
This commit is contained in:
Konstantin Raev 2016-06-10 11:41:50 -07:00 committed by Facebook Github Bot 2
parent 4f4b6d467a
commit 0d572e40f0

View File

@ -210,6 +210,7 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim
// Animation // Animation
RCTLayoutAnimation *_layoutAnimation; // Main thread only RCTLayoutAnimation *_layoutAnimation; // Main thread only
NSMutableSet<UIView *> *_viewsToBeDeleted; // Main thread only
NSMutableDictionary<NSNumber *, RCTShadowView *> *_shadowViewRegistry; // RCT thread only NSMutableDictionary<NSNumber *, RCTShadowView *> *_shadowViewRegistry; // RCT thread only
NSMutableDictionary<NSNumber *, UIView *> *_viewRegistry; // Main thread only NSMutableDictionary<NSNumber *, UIView *> *_viewRegistry; // Main thread only
@ -318,6 +319,8 @@ RCT_EXPORT_MODULE()
_bridgeTransactionListeners = [NSMutableSet new]; _bridgeTransactionListeners = [NSMutableSet new];
_viewsToBeDeleted = [NSMutableSet new];
// Get view managers from bridge // Get view managers from bridge
NSMutableDictionary *componentDataByName = [NSMutableDictionary new]; NSMutableDictionary *componentDataByName = [NSMutableDictionary new];
for (Class moduleClass in _bridge.moduleClasses) { for (Class moduleClass in _bridge.moduleClasses) {
@ -339,7 +342,6 @@ RCT_EXPORT_MODULE()
selector:@selector(interfaceOrientationWillChange:) selector:@selector(interfaceOrientationWillChange:)
name:UIApplicationWillChangeStatusBarOrientationNotification name:UIApplicationWillChangeStatusBarOrientationNotification
object:nil]; object:nil];
[RCTAnimation initializeStatics]; [RCTAnimation initializeStatics];
} }
@ -778,53 +780,61 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(nonnull NSNumber *)containe
- (void)_removeChildren:(NSArray<id<RCTComponent>> *)children - (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
fromContainer:(id<RCTComponent>)container fromContainer:(id<RCTComponent>)container
permanent:(BOOL)permanent
{ {
RCTLayoutAnimation *layoutAnimation = _layoutAnimation; for (id<RCTComponent> removedChild in children) {
RCTAnimation *deleteAnimation = layoutAnimation.deleteAnimation; [container removeReactSubview:removedChild];
}
}
/**
* Remove subviews from their parent with an animation.
*/
- (void)_removeChildren:(NSArray<UIView *> *)children
fromContainer:(UIView *)container
withAnimation:(RCTLayoutAnimation *)animation
{
RCTAssertMainQueue();
RCTAnimation *deleteAnimation = animation.deleteAnimation;
__block NSUInteger completionsCalled = 0; __block NSUInteger completionsCalled = 0;
for (UIView *removedChild in children) {
for (id<RCTComponent> removedChild in children) {
void (^completion)(BOOL) = ^(BOOL finished) { void (^completion)(BOOL) = ^(BOOL finished) {
completionsCalled++; completionsCalled++;
[_viewsToBeDeleted removeObject:removedChild];
[container removeReactSubview:removedChild]; [container removeReactSubview:removedChild];
if (layoutAnimation.callback && completionsCalled == children.count) { if (animation.callback && completionsCalled == children.count) {
layoutAnimation.callback(@[@(finished)]); animation.callback(@[@(finished)]);
// It's unsafe to call this callback more than once, so we nil it out here // It's unsafe to call this callback more than once, so we nil it out here
// to make sure that doesn't happen. // to make sure that doesn't happen.
layoutAnimation.callback = nil; animation.callback = nil;
} }
}; };
if (permanent && deleteAnimation && [removedChild isKindOfClass: [UIView class]]) { [_viewsToBeDeleted addObject:removedChild];
UIView *view = (UIView *)removedChild;
// Disable user interaction while the view is animating since JS won't receive // Disable user interaction while the view is animating since JS won't receive
// the view events anyway. // the view events anyway.
view.userInteractionEnabled = NO; removedChild.userInteractionEnabled = NO;
NSString *property = deleteAnimation.property; NSString *property = deleteAnimation.property;
[deleteAnimation performAnimations:^{ [deleteAnimation performAnimations:^{
if ([property isEqualToString:@"scaleXY"]) { if ([property isEqualToString:@"scaleXY"]) {
view.layer.transform = CATransform3DMakeScale(0, 0, 0); removedChild.layer.transform = CATransform3DMakeScale(0, 0, 0);
} else if ([property isEqualToString:@"opacity"]) { } else if ([property isEqualToString:@"opacity"]) {
view.layer.opacity = 0.0; removedChild.layer.opacity = 0.0;
} else { } else {
RCTLogError(@"Unsupported layout animation createConfig property %@", RCTLogError(@"Unsupported layout animation createConfig property %@",
deleteAnimation.property); deleteAnimation.property);
} }
} withCompletionBlock:completion]; } withCompletionBlock:completion];
} else {
[container removeReactSubview:removedChild];
}
} }
} }
RCT_EXPORT_METHOD(removeRootView:(nonnull NSNumber *)rootReactTag) RCT_EXPORT_METHOD(removeRootView:(nonnull NSNumber *)rootReactTag)
{ {
RCTShadowView *rootShadowView = _shadowViewRegistry[rootReactTag]; RCTShadowView *rootShadowView = _shadowViewRegistry[rootReactTag];
@ -938,13 +948,19 @@ RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerTag
[self _childrenToRemoveFromContainer:container atIndices:removeAtIndices]; [self _childrenToRemoveFromContainer:container atIndices:removeAtIndices];
NSArray<id<RCTComponent>> *temporarilyRemovedChildren = NSArray<id<RCTComponent>> *temporarilyRemovedChildren =
[self _childrenToRemoveFromContainer:container atIndices:moveFromIndices]; [self _childrenToRemoveFromContainer:container atIndices:moveFromIndices];
[self _removeChildren:permanentlyRemovedChildren fromContainer:container permanent:true];
[self _removeChildren:temporarilyRemovedChildren fromContainer:container permanent:false];
BOOL isUIViewRegistry = ((id)registry == (id)_viewRegistry);
if (isUIViewRegistry && _layoutAnimation.deleteAnimation) {
[self _removeChildren:(NSArray<UIView *> *)permanentlyRemovedChildren
fromContainer:(UIView *)container
withAnimation:_layoutAnimation];
} else {
[self _removeChildren:permanentlyRemovedChildren fromContainer:container];
}
[self _removeChildren:temporarilyRemovedChildren fromContainer:container];
[self _purgeChildren:permanentlyRemovedChildren fromRegistry:registry]; [self _purgeChildren:permanentlyRemovedChildren fromRegistry:registry];
// TODO (#5906496): optimize all these loops - constantly calling array.count is not efficient
// Figure out what to insert - merge temporary inserts and adds // Figure out what to insert - merge temporary inserts and adds
NSMutableDictionary *destinationsToChildrenToAdd = [NSMutableDictionary dictionary]; NSMutableDictionary *destinationsToChildrenToAdd = [NSMutableDictionary dictionary];
for (NSInteger index = 0, length = temporarilyRemovedChildren.count; index < length; index++) { for (NSInteger index = 0, length = temporarilyRemovedChildren.count; index < length; index++) {
@ -960,8 +976,22 @@ RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerTag
NSArray<NSNumber *> *sortedIndices = NSArray<NSNumber *> *sortedIndices =
[destinationsToChildrenToAdd.allKeys sortedArrayUsingSelector:@selector(compare:)]; [destinationsToChildrenToAdd.allKeys sortedArrayUsingSelector:@selector(compare:)];
for (NSNumber *reactIndex in sortedIndices) { for (NSNumber *reactIndex in sortedIndices) {
NSInteger insertAtIndex = reactIndex.integerValue;
// When performing a delete animation, views are not removed immediately
// from their container so we need to offset the insertion index if a view
// that will be removed appears earlier than the view we are inserting.
if (isUIViewRegistry && _viewsToBeDeleted.count > 0) {
for (NSInteger index = 0; index < insertAtIndex; index++) {
UIView *subview = ((UIView *)container).reactSubviews[index];
if ([_viewsToBeDeleted containsObject:subview]) {
insertAtIndex++;
}
}
}
[container insertReactSubview:destinationsToChildrenToAdd[reactIndex] [container insertReactSubview:destinationsToChildrenToAdd[reactIndex]
atIndex:reactIndex.integerValue]; atIndex:insertAtIndex];
} }
} }