@@ -57,8 +57,6 @@ @interface RCTAnimation : NSObject
57
57
@property (nonatomic , readonly ) NSTimeInterval duration;
58
58
@property (nonatomic , readonly ) NSTimeInterval delay;
59
59
@property (nonatomic , readonly , copy ) NSString *property;
60
- @property (nonatomic , readonly ) id fromValue;
61
- @property (nonatomic , readonly ) id toValue;
62
60
@property (nonatomic , readonly ) CGFloat springDamping;
63
61
@property (nonatomic , readonly ) CGFloat initialVelocity;
64
62
@property (nonatomic , readonly ) RCTAnimationType animationType;
@@ -136,8 +134,6 @@ - (instancetype)initWithDuration:(NSTimeInterval)duration dictionary:(NSDictiona
136
134
_springDamping = [RCTConvert CGFloat: config[@" springDamping" ]];
137
135
_initialVelocity = [RCTConvert CGFloat: config[@" initialVelocity" ]];
138
136
}
139
- _fromValue = config[@" fromValue" ];
140
- _toValue = config[@" toValue" ];
141
137
}
142
138
return self;
143
139
}
@@ -552,42 +548,47 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *
552
548
return nil ;
553
549
}
554
550
555
- // Parallel arrays are built and then handed off to main thread
556
- NSMutableArray <NSNumber *> *frameReactTags =
557
- [NSMutableArray arrayWithCapacity: viewsWithNewFrames.count];
558
- NSMutableArray <NSValue *> *frames =
559
- [NSMutableArray arrayWithCapacity: viewsWithNewFrames.count];
560
- NSMutableArray <NSNumber *> *areNew =
561
- [NSMutableArray arrayWithCapacity: viewsWithNewFrames.count];
562
- NSMutableArray <NSNumber *> *parentsAreNew =
563
- [NSMutableArray arrayWithCapacity: viewsWithNewFrames.count];
564
- NSMutableDictionary <NSNumber *, RCTViewManagerUIBlock> *updateBlocks =
565
- [NSMutableDictionary new ];
566
- NSMutableArray <NSNumber *> *areHidden =
567
- [NSMutableArray arrayWithCapacity: viewsWithNewFrames.count];
568
-
569
- for (RCTShadowView *shadowView in viewsWithNewFrames) {
570
- [frameReactTags addObject: shadowView.reactTag];
571
- [frames addObject: [NSValue valueWithCGRect: shadowView.frame]];
572
- [areNew addObject: @(shadowView.isNewView)];
573
- [parentsAreNew addObject: @(shadowView.superview.isNewView)];
574
- [areHidden addObject: @(shadowView.isHidden)];
575
- }
576
-
577
- for (RCTShadowView *shadowView in viewsWithNewFrames) {
578
- // We have to do this after we build the parentsAreNew array.
579
- shadowView.newView = NO ;
551
+ typedef struct {
552
+ CGRect frame;
553
+ BOOL isNew;
554
+ BOOL parentIsNew;
555
+ BOOL isHidden;
556
+ } RCTFrameData;
557
+
558
+ // Construct arrays then hand off to main thread
559
+ NSInteger count = viewsWithNewFrames.count ;
560
+ NSMutableArray *reactTags = [[NSMutableArray alloc ] initWithCapacity: count];
561
+ NSMutableData *framesData = [[NSMutableData alloc ] initWithLength: sizeof (RCTFrameData) * count];
562
+ {
563
+ NSInteger index = 0 ;
564
+ RCTFrameData *frameDataArray = (RCTFrameData *)framesData.mutableBytes ;
565
+ for (RCTShadowView *shadowView in viewsWithNewFrames) {
566
+ reactTags[index] = shadowView.reactTag ;
567
+ frameDataArray[index++] = (RCTFrameData){
568
+ shadowView.frame ,
569
+ shadowView.isNewView ,
570
+ shadowView.superview .isNewView ,
571
+ shadowView.isHidden ,
572
+ };
573
+ }
580
574
}
581
575
582
576
// These are blocks to be executed on each view, immediately after
583
577
// reactSetFrame: has been called. Note that if reactSetFrame: is not called,
584
578
// these won't be called either, so this is not a suitable place to update
585
579
// properties that aren't related to layout.
580
+ NSMutableDictionary <NSNumber *, RCTViewManagerUIBlock> *updateBlocks =
581
+ [NSMutableDictionary new ];
586
582
for (RCTShadowView *shadowView in viewsWithNewFrames) {
583
+
584
+ // We have to do this after we build the parentsAreNew array.
585
+ shadowView.newView = NO ;
586
+
587
+ NSNumber *reactTag = shadowView.reactTag ;
587
588
RCTViewManager *manager = [_componentDataByName[shadowView.viewName] manager ];
588
589
RCTViewManagerUIBlock block = [manager uiBlockToAmendWithShadowView: shadowView];
589
590
if (block) {
590
- updateBlocks[shadowView. reactTag] = block;
591
+ updateBlocks[reactTag] = block;
591
592
}
592
593
593
594
if (shadowView.onLayout ) {
@@ -602,8 +603,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *
602
603
});
603
604
}
604
605
605
- if (RCTIsReactRootView (shadowView.reactTag )) {
606
- NSNumber *reactTag = shadowView.reactTag ;
606
+ if (RCTIsReactRootView (reactTag)) {
607
607
CGSize contentSize = shadowView.frame .size ;
608
608
609
609
dispatch_async (dispatch_get_main_queue (), ^{
@@ -618,87 +618,107 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *
618
618
619
619
// Perform layout (possibly animated)
620
620
return ^(__unused RCTUIManager *uiManager, NSDictionary <NSNumber *, UIView *> *viewRegistry) {
621
- RCTLayoutAnimation *layoutAnimation = _layoutAnimation;
622
-
623
- __block NSUInteger completionsCalled = 0 ;
624
- for (NSUInteger ii = 0 ; ii < frames.count ; ii++) {
625
- NSNumber *reactTag = frameReactTags[ii];
626
- UIView *view = viewRegistry[reactTag];
627
- CGRect frame = [frames[ii] CGRectValue ];
628
-
629
- BOOL isHidden = [areHidden[ii] boolValue ];
630
- BOOL isNew = [areNew[ii] boolValue ];
631
- RCTAnimation *updateAnimation = isNew ? nil : layoutAnimation.updateAnimation ;
632
- BOOL shouldAnimateCreation = isNew && ![parentsAreNew[ii] boolValue ];
633
- RCTAnimation *createAnimation = shouldAnimateCreation ? layoutAnimation.createAnimation : nil ;
634
-
635
- void (^completion)(BOOL ) = ^(BOOL finished) {
636
- completionsCalled++;
637
- if (layoutAnimation.callback && completionsCalled == frames.count ) {
638
- layoutAnimation.callback (@[@(finished)]);
639
-
640
- // It's unsafe to call this callback more than once, so we nil it out here
641
- // to make sure that doesn't happen.
642
- layoutAnimation.callback = nil ;
643
- }
644
- };
645
621
646
- if (view.isHidden != isHidden) {
647
- view.hidden = isHidden;
648
- }
622
+ const RCTFrameData *frameDataArray = (const RCTFrameData *)framesData.bytes ;
649
623
650
- // Animate view creation
651
- if (createAnimation) {
624
+ RCTLayoutAnimation *layoutAnimation = uiManager->_layoutAnimation ;
625
+ if (!layoutAnimation.updateAnimation && !layoutAnimation.createAnimation ) {
626
+
627
+ // Fast path for common case
628
+ NSInteger index = 0 ;
629
+ for (NSNumber *reactTag in reactTags) {
630
+ RCTFrameData frameData = frameDataArray[index++];
631
+
632
+ UIView *view = viewRegistry[reactTag];
633
+ CGRect frame = frameData.frame ;
652
634
[view reactSetFrame: frame];
653
635
654
- CATransform3D finalTransform = view.layer .transform ;
655
- CGFloat finalOpacity = view.layer .opacity ;
656
- if ([createAnimation.property isEqualToString: @" scaleXY" ]) {
657
- view.layer .transform = CATransform3DMakeScale (0 , 0 , 0 );
658
- } else if ([createAnimation.property isEqualToString: @" opacity" ]) {
659
- view.layer .opacity = 0.0 ;
636
+ RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
637
+ if (updateBlock) {
638
+ updateBlock (self, viewRegistry);
660
639
}
640
+ }
641
+ if (layoutAnimation.callback ) {
642
+ layoutAnimation.callback (@[@YES ]);
643
+ }
661
644
662
- [createAnimation performAnimations: ^{
663
- if ([createAnimation.property isEqual: @" scaleXY" ]) {
664
- view.layer .transform = finalTransform;
665
- } else if ([createAnimation.property isEqual: @" opacity" ]) {
666
- view.layer .opacity = finalOpacity;
667
- } else {
668
- RCTLogError (@" Unsupported layout animation createConfig property %@ " ,
669
- createAnimation.property );
670
- }
645
+ } else {
646
+
647
+ __block NSUInteger completionsCalled = 0 ;
648
+
649
+ NSInteger index = 0 ;
650
+ for (NSNumber *reactTag in reactTags) {
651
+ RCTFrameData frameData = frameDataArray[index++];
652
+
653
+ UIView *view = viewRegistry[reactTag];
654
+ CGRect frame = frameData.frame ;
655
+
656
+ BOOL isNew = frameData.isNew ;
657
+ RCTAnimation *updateAnimation = isNew ? nil : layoutAnimation.updateAnimation ;
658
+ BOOL shouldAnimateCreation = isNew && !frameData.parentIsNew ;
659
+ RCTAnimation *createAnimation = shouldAnimateCreation ? layoutAnimation.createAnimation : nil ;
660
+
661
+ BOOL isHidden = frameData.isHidden ;
662
+ if (view.isHidden != isHidden) {
663
+ view.hidden = isHidden;
664
+ }
671
665
672
- RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
673
- if (updateBlock) {
674
- updateBlock (self, _viewRegistry);
666
+ void (^completion)(BOOL ) = ^(BOOL finished) {
667
+ completionsCalled++;
668
+ if (layoutAnimation.callback && completionsCalled == count) {
669
+ layoutAnimation.callback (@[@(finished)]);
670
+
671
+ // It's unsafe to call this callback more than once, so we nil it out here
672
+ // to make sure that doesn't happen.
673
+ layoutAnimation.callback = nil ;
675
674
}
676
- } withCompletionBlock: completion];
675
+ };
676
+
677
+ RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
678
+ if (createAnimation) {
677
679
678
- // Animate view update
679
- } else if (updateAnimation) {
680
- [updateAnimation performAnimations: ^{
680
+ // Animate view creation
681
681
[view reactSetFrame: frame];
682
682
683
- RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
684
- if (updateBlock) {
685
- updateBlock (self, _viewRegistry);
686
- }
687
- } withCompletionBlock: completion];
683
+ CATransform3D finalTransform = view.layer .transform ;
684
+ CGFloat finalOpacity = view.layer .opacity ;
688
685
689
- // Update without animation
690
- } else {
691
- [view reactSetFrame: frame];
686
+ NSString *property = createAnimation.property ;
687
+ if ([property isEqualToString: @" scaleXY" ]) {
688
+ view.layer .transform = CATransform3DMakeScale (0 , 0 , 0 );
689
+ } else if ([property isEqualToString: @" opacity" ]) {
690
+ view.layer .opacity = 0.0 ;
691
+ } else {
692
+ RCTLogError (@" Unsupported layout animation createConfig property %@ " ,
693
+ createAnimation.property );
694
+ }
692
695
693
- RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
694
- if (updateBlock) {
695
- updateBlock (self, _viewRegistry);
696
+ [createAnimation performAnimations: ^{
697
+ if ([property isEqualToString: @" scaleXY" ]) {
698
+ view.layer .transform = finalTransform;
699
+ } else if ([property isEqualToString: @" opacity" ]) {
700
+ view.layer .opacity = finalOpacity;
701
+ }
702
+ if (updateBlock) {
703
+ updateBlock (self, viewRegistry);
704
+ }
705
+ } withCompletionBlock: completion];
706
+
707
+ } else if (updateAnimation) {
708
+
709
+ // Animate view update
710
+ [updateAnimation performAnimations: ^{
711
+ [view reactSetFrame: frame];
712
+ if (updateBlock) {
713
+ updateBlock (self, viewRegistry);
714
+ }
715
+ } withCompletionBlock: completion];
696
716
}
697
- completion (YES );
698
717
}
699
718
}
700
719
701
- _layoutAnimation = nil ;
720
+ // Clean up
721
+ uiManager->_layoutAnimation = nil ;
702
722
};
703
723
}
704
724
@@ -802,10 +822,11 @@ - (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
802
822
// the view events anyway.
803
823
view.userInteractionEnabled = NO ;
804
824
825
+ NSString *property = deleteAnimation.property ;
805
826
[deleteAnimation performAnimations: ^{
806
- if ([deleteAnimation. property isEqual :@" scaleXY" ]) {
827
+ if ([property isEqualToString :@" scaleXY" ]) {
807
828
view.layer .transform = CATransform3DMakeScale (0 , 0 , 0 );
808
- } else if ([deleteAnimation. property isEqual :@" opacity" ]) {
829
+ } else if ([property isEqualToString :@" opacity" ]) {
809
830
view.layer .opacity = 0.0 ;
810
831
} else {
811
832
RCTLogError (@" Unsupported layout animation createConfig property %@ " ,
0 commit comments