Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions ios/LayoutReanimation/REAAnimationsManager.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import <RNReanimated/REAAnimationsManager.h>
#import <RNReanimated/REASharedElement.h>
#import <RNReanimated/REASharedTransitionManager.h>
#import <RNReanimated/REAUIManager.h>
#import <RNReanimated/REASwizzledUIManager.h>
#import <React/RCTComponentData.h>
#import <React/RCTTextView.h>
#import <React/UIView+Private.h>
Expand Down Expand Up @@ -30,7 +30,7 @@ BOOL REANodeFind(id<RCTComponent> view, int (^block)(id<RCTComponent>))

@implementation REAAnimationsManager {
RCTUIManager *_uiManager;
REAUIManager *_reaUiManager;
REASwizzledUIManager *_reaSwizzledUIManager;
NSMutableSet<NSNumber *> *_enteringViews;
NSMutableDictionary<NSNumber *, REASnapshot *> *_enteringViewTargetValues;
NSMutableDictionary<NSNumber *, UIView *> *_exitingViews;
Expand Down Expand Up @@ -59,7 +59,6 @@ - (instancetype)initWithUIManager:(RCTUIManager *)uiManager
{
if (self = [super init]) {
_uiManager = uiManager;
_reaUiManager = (REAUIManager *)uiManager;
_exitingViews = [NSMutableDictionary new];
_exitingSubviewsCountMap = [NSMutableDictionary new];
_ancestorsToRemove = [NSMutableSet new];
Expand All @@ -74,6 +73,7 @@ - (instancetype)initWithUIManager:(RCTUIManager *)uiManager
[_currentKeys addObject:[NSString stringWithFormat:@"current%@", [key capitalizedString]]];
}
_sharedTransitionManager = [[REASharedTransitionManager alloc] initWithAnimationsManager:self];
_reaSwizzledUIManager = [[REASwizzledUIManager alloc] initWithUIManager:uiManager withAnimatioinManager:self];
Comment thread
piaskowyk marked this conversation as resolved.
Outdated
}
return self;
}
Expand Down Expand Up @@ -106,7 +106,7 @@ - (void)setAnimationRemovingBlock:(REAAnimationRemovingBlock)clearAnimation
- (UIView *)viewForTag:(NSNumber *)tag
{
UIView *view;
(view = [_reaUiManager viewForReactTag:tag]) || (view = [_exitingViews objectForKey:tag]) ||
(view = [_uiManager viewForReactTag:tag]) || (view = [_exitingViews objectForKey:tag]) ||
(view = [_sharedTransitionManager getTransitioningView:tag]);
return view;
}
Expand Down
6 changes: 6 additions & 0 deletions ios/LayoutReanimation/REASwizzledUIManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#import <RNReanimated/REAAnimationsManager.h>

@interface REASwizzledUIManager : NSObject
- (instancetype)initWithUIManager:(RCTUIManager *)uiManager
withAnimatioinManager:(REAAnimationsManager *)animationsManager;
@end
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#import <Foundation/Foundation.h>
#import <RNReanimated/FeaturesConfig.h>
#import <RNReanimated/REAIOSScheduler.h>
#import <RNReanimated/REAUIManager.h>
#import <RNReanimated/REASwizzledUIManager.h>
#import <RNReanimated/REAUtils.h>
#import <RNReanimated/Scheduler.h>
#import <React/RCTComponentData.h>
#import <React/RCTLayoutAnimation.h>
Expand All @@ -16,76 +17,65 @@
#endif

@interface RCTUIManager (REA)
- (void)_manageChildren:(NSNumber *)containerTag
moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
moveToIndices:(NSArray<NSNumber *> *)moveToIndices
addChildReactTags:(NSArray<NSNumber *> *)addChildReactTags
addAtIndices:(NSArray<NSNumber *> *)addAtIndices
removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices
registry:(NSMutableDictionary<NSNumber *, id<RCTComponent>> *)registry;

- (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *)rootShadowView;

- (NSArray<id<RCTComponent>> *)_childrenToRemoveFromContainer:(id<RCTComponent>)container
atIndices:(NSArray<NSNumber *> *)atIndices;
@end

@implementation REAUIManager {
NSMutableDictionary<NSNumber *, NSMutableSet<id<RCTComponent>> *> *_toBeRemovedRegister;
NSMutableDictionary<NSNumber *, NSNumber *> *_parentMapper;
@implementation REASwizzledUIManager {
REAAnimationsManager *_animationsManager;
std::weak_ptr<reanimated::Scheduler> _scheduler;
RCTUIManager *_uiManager;
}

+ (NSString *)moduleName
{
return NSStringFromClass([RCTUIManager class]);
}
static REASwizzledUIManager *_reaUIManager;

- (void)invalidate
- (instancetype)initWithUIManager:(RCTUIManager *)uiManager
withAnimatioinManager:(REAAnimationsManager *)animationsManager
{
[_animationsManager invalidate];
[super invalidate];
if (self = [super init]) {
_animationsManager = animationsManager;
_uiManager = uiManager;
_reaUIManager = self;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand the need for this whole REASwizzledUIManager class to exists. Also, assigning singletons like that seem a bit risky.

It seem to me that the reason it's been done this way was for the swizzled methods to be able to access _uiManager and _animationsManager fields. I think the former can just be replaced by self as the swizzling concept refers to swapping out implementation of certain methods. The UI manager object will be the same and the swizzled method self will refer to it.

As for the latter field, the best way IMO would be to use category on UIManager class that adds animationsManager property to it using associated object technique (https://nshipster.com/associated-objects/)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I've made the changes based on your suggestions 👍. I dumped the singleton and used associated objects with the category instead.
  2. The only reason I created the REASwizzledUIManager class was to keep the swizzled methods separate from the animation manager. I didn't want to put everything into one file. But yeah, if you think it's best, I can move the _manageChildren and _uiBlockWithLayoutUpdateForRootView methods back to the REAAnimationManager class.

[self swizzleMethods];
}
return self;
}

- (void)setBridge:(RCTBridge *)bridge
- (void)swizzleMethods
{
if (!_blockSetter) {
_blockSetter = true;

self.bridge = bridge;
[super setValue:bridge forKey:@"_bridge"];
[self setValue:[bridge.uiManager valueForKey:@"_shadowViewRegistry"] forKey:@"_shadowViewRegistry"];
[self setValue:[bridge.uiManager valueForKey:@"_viewRegistry"] forKey:@"_viewRegistry"];
[self setValue:[bridge.uiManager valueForKey:@"_nativeIDRegistry"] forKey:@"_nativeIDRegistry"];
[self setValue:[bridge.uiManager valueForKey:@"_shadowViewsWithUpdatedProps"]
forKey:@"_shadowViewsWithUpdatedProps"];
[self setValue:[bridge.uiManager valueForKey:@"_shadowViewsWithUpdatedChildren"]
forKey:@"_shadowViewsWithUpdatedChildren"];
[self setValue:[bridge.uiManager valueForKey:@"_pendingUIBlocks"] forKey:@"_pendingUIBlocks"];
[self setValue:[bridge.uiManager valueForKey:@"_rootViewTags"] forKey:@"_rootViewTags"];
[self setValue:[bridge.uiManager valueForKey:@"_observerCoordinator"] forKey:@"_observerCoordinator"];
[self setValue:[bridge.uiManager valueForKey:@"_componentDataByName"] forKey:@"_componentDataByName"];

_blockSetter = false;
}
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[REAUtils swizzleMethod:@selector(uiBlockWithLayoutUpdateForRootView:)
forClass:[RCTUIManager class]
with:@selector(reanimated_uiBlockWithLayoutUpdateForRootView:)
fromClass:[self class]];
SEL manageChildrenOriginal = @selector
(_manageChildren:moveFromIndices:moveToIndices:addChildReactTags:addAtIndices:removeAtIndices:registry:);
SEL manageChildrenReaniamted =
@selector(reanimated_manageChildren:
moveFromIndices:moveToIndices:addChildReactTags:addAtIndices:removeAtIndices:registry:);
[REAUtils swizzleMethod:manageChildrenOriginal
forClass:[RCTUIManager class]
with:manageChildrenReaniamted
Comment thread
piaskowyk marked this conversation as resolved.
Outdated
fromClass:[self class]];
});
}

- (void)_manageChildren:(NSNumber *)containerTag
moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
moveToIndices:(NSArray<NSNumber *> *)moveToIndices
addChildReactTags:(NSArray<NSNumber *> *)addChildReactTags
addAtIndices:(NSArray<NSNumber *> *)addAtIndices
removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices
registry:(NSMutableDictionary<NSNumber *, id<RCTComponent>> *)registry
- (void)reanimated_manageChildren:(NSNumber *)containerTag
moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
moveToIndices:(NSArray<NSNumber *> *)moveToIndices
addChildReactTags:(NSArray<NSNumber *> *)addChildReactTags
addAtIndices:(NSArray<NSNumber *> *)addAtIndices
removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices
registry:(NSMutableDictionary<NSNumber *, id<RCTComponent>> *)registry
{
bool isLayoutAnimationEnabled = reanimated::FeaturesConfig::isLayoutAnimationEnabled();
id<RCTComponent> container;
NSArray<id<RCTComponent>> *permanentlyRemovedChildren;
BOOL containerIsRootOfViewController = NO;
if (isLayoutAnimationEnabled) {
container = registry[containerTag];
permanentlyRemovedChildren = [self _childrenToRemoveFromContainer:container atIndices:removeAtIndices];
permanentlyRemovedChildren = [_reaUIManager->_uiManager _childrenToRemoveFromContainer:container
atIndices:removeAtIndices];

if ([container isKindOfClass:[UIView class]]) {
UIViewController *controller = ((UIView *)container).reactViewController;
Expand All @@ -97,22 +87,23 @@ - (void)_manageChildren:(NSNumber *)containerTag
// of some view controller. In that case, we skip running exiting animations
// in its children, to prevent issues with RN Screens.
if (containerIsRootOfViewController) {
NSArray<id<RCTComponent>> *permanentlyRemovedChildren = [self _childrenToRemoveFromContainer:container
atIndices:removeAtIndices];
NSArray<id<RCTComponent>> *permanentlyRemovedChildren =
[_reaUIManager->_uiManager _childrenToRemoveFromContainer:container atIndices:removeAtIndices];
for (UIView *view in permanentlyRemovedChildren) {
[_animationsManager endAnimationsRecursive:view];
[_reaUIManager->_animationsManager endAnimationsRecursive:view];
}
[_animationsManager removeAnimationsFromSubtree:(UIView *)container];
[_reaUIManager->_animationsManager removeAnimationsFromSubtree:(UIView *)container];
}
}

[super _manageChildren:containerTag
moveFromIndices:moveFromIndices
moveToIndices:moveToIndices
addChildReactTags:addChildReactTags
addAtIndices:addAtIndices
removeAtIndices:removeAtIndices
registry:registry];
// call original method
[self reanimated_manageChildren:containerTag
moveFromIndices:moveFromIndices
moveToIndices:moveToIndices
addChildReactTags:addChildReactTags
addAtIndices:addAtIndices
removeAtIndices:removeAtIndices
registry:registry];

if (!isLayoutAnimationEnabled) {
return;
Expand All @@ -132,25 +123,15 @@ - (void)_manageChildren:(NSNumber *)containerTag
return [(NSNumber *)obj1[0] compare:(NSNumber *)obj2[0]];
}];

[_animationsManager reattachAnimatedChildren:permanentlyRemovedChildren
toContainer:container
atIndices:removeAtIndices];
}

- (void)callAnimationForTree:(UIView *)view parentTag:(NSNumber *)parentTag
{
_parentMapper[view.reactTag] = parentTag;

for (UIView *subView in view.reactSubviews) {
[self callAnimationForTree:subView parentTag:view.reactTag];
}
[_reaUIManager->_animationsManager reattachAnimatedChildren:permanentlyRemovedChildren
toContainer:container
atIndices:removeAtIndices];
}

// Overrided https://github.com/facebook/react-native/blob/v0.65.0/React/Modules/RCTUIManager.m#L530
- (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *)rootShadowView
- (RCTViewManagerUIBlock)reanimated_uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *)rootShadowView
{
if (!reanimated::FeaturesConfig::isLayoutAnimationEnabled()) {
return [super uiBlockWithLayoutUpdateForRootView:rootShadowView];
return [self reanimated_uiBlockWithLayoutUpdateForRootView:rootShadowView];
}

NSHashTable<RCTShadowView *> *affectedShadowViews = [NSHashTable weakObjectsHashTable];
Expand Down Expand Up @@ -266,7 +247,8 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *
}

// Reanimated changes /start
REASnapshot *snapshotBefore = isNew ? nil : [self->_animationsManager prepareSnapshotBeforeMountForView:view];
REASnapshot *snapshotBefore =
isNew ? nil : [_reaUIManager->_animationsManager prepareSnapshotBeforeMountForView:view];
snapshotsBefore[reactTag] = snapshotBefore;
// Reanimated changes /end

Expand Down Expand Up @@ -327,7 +309,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *
REASnapshot *snapshotBefore = snapshotsBefore[reactTag];

if (isNew || snapshotBefore != nil) {
[self->_animationsManager viewDidMount:view withBeforeSnapshot:snapshotBefore withNewFrame:frame];
[_reaUIManager->_animationsManager viewDidMount:view withBeforeSnapshot:snapshotBefore withNewFrame:frame];
}
}

Expand All @@ -336,52 +318,9 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *
// private field
[uiManager setNextLayoutAnimationGroup:nil];

[self->_animationsManager viewsDidLayout];
[_reaUIManager->_animationsManager viewsDidLayout];
// Reanimated changes /end
};
}

- (Class)class
{
return [RCTUIManager class];
}

+ (Class)class
{
return [RCTUIManager class];
}

- (void)setUp:(REAAnimationsManager *)animationsManager
{
_animationsManager = animationsManager;
_toBeRemovedRegister = [[NSMutableDictionary<NSNumber *, NSMutableSet<id<RCTComponent>> *> alloc] init];
_parentMapper = [[NSMutableDictionary<NSNumber *, NSNumber *> alloc] init];
}

- (void)unregisterView:(id<RCTComponent>)view
{
NSNumber *tag = _parentMapper[view.reactTag];
if (tag == nil) {
return;
}

[_toBeRemovedRegister[tag] removeObject:view];
if (_toBeRemovedRegister[tag].count == 0) {
[_toBeRemovedRegister removeObjectForKey:tag];
}
NSMutableDictionary<NSNumber *, id<RCTComponent>> *viewRegistry = [self valueForKey:@"_viewRegistry"];
[view.reactSuperview removeReactSubview:view];
id<RCTComponent> parentView = viewRegistry[tag];
@try {
[parentView removeReactSubview:view];
} @catch (id anException) {
}
#if __has_include(<RNScreens/RNSScreen.h>)
if ([view isKindOfClass:[RNSScreenView class]]) {
[parentView didUpdateReactSubviews];
}
#endif
[viewRegistry removeObjectForKey:view.reactTag];
}

@end
16 changes: 0 additions & 16 deletions ios/LayoutReanimation/REAUIManager.h

This file was deleted.

2 changes: 2 additions & 0 deletions ios/REAModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
#import <React/RCTUIManagerObserverCoordinator.h>
#import <React/RCTUIManagerUtils.h>

#import <RNReanimated/REAAnimationsManager.h>
#import <RNReanimated/REANodesManager.h>

@interface REAModule : RCTEventEmitter <RCTBridgeModule, RCTEventDispatcherObserver, RCTUIManagerObserver>

@property (nonatomic, readonly) REANodesManager *nodesManager;
@property REAAnimationsManager *animationsManager;

#ifdef RCT_NEW_ARCH_ENABLED
- (void)installReanimatedAfterReload;
Expand Down
1 change: 1 addition & 0 deletions ios/REAModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ - (void)setBridge:(RCTBridge *)bridge
_operations = [NSMutableArray new];

[bridge.uiManager.observerCoordinator addObserver:self];
_animationsManager = [[REAAnimationsManager alloc] initWithUIManager:bridge.uiManager];
}

#pragma mark-- Batch handling
Expand Down
7 changes: 7 additions & 0 deletions ios/REAUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@
if (value == nil) \
RCTLogError(errorMsg); \
})

@interface REAUtils : NSObject
Comment thread
piaskowyk marked this conversation as resolved.
Outdated
+ (void)swizzleMethod:(SEL)originalSelector
forClass:(Class)originalClass
with:(SEL)newSelector
fromClass:(Class)newClass;
@end
19 changes: 19 additions & 0 deletions ios/REAUtils.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#import <REAUtils.h>
#import <objc/runtime.h>

@implementation REAUtils

+ (void)swizzleMethod:(SEL)originalSelector
forClass:(Class)originalClass
with:(SEL)newSelector
fromClass:(Class)newClass
{
Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
Method newMethod = class_getInstanceMethod(newClass, newSelector);
IMP originalImplementation = method_getImplementation(originalMethod);
IMP newImplementation = method_getImplementation(newMethod);
class_replaceMethod(originalClass, newSelector, originalImplementation, method_getTypeEncoding(originalMethod));
class_replaceMethod(originalClass, originalSelector, newImplementation, method_getTypeEncoding(newMethod));
}

@end
Loading