Use surface observer for Animated

Summary:
Right now we rely on the Paper UIManager to update animated node graphs - this hooks us into `RCTSurfacePresenter` in the same way so we are no longer reliant on Paper. Should also help with complex ordering corner cases with pre vs. post operations and restoring defaults when nodes are removed. More info:

https://github.com/facebook/react-native/pull/11819/files

Note that we don't have a way to differentiate animation nodes related to fabric views vs. paper views, so if paper and fabric are both rendering updates simultaneously it's possible they could get processed by the wrong callback. That should be very rare, rarely cause problems even if it does happen, and won't be a problem at all in a post-Paper world.

Reviewed By: shergin

Differential Revision: D14336760

fbshipit-source-id: 1c6a72fa67d5fedbaefb21cd4d7e5d75484f4fae
This commit is contained in:
Spencer Ahrens
2019-03-07 17:34:41 -08:00
committed by Facebook Github Bot
parent 3e40837a85
commit 544d9fb10b
7 changed files with 117 additions and 24 deletions

View File

@@ -7,33 +7,14 @@
#import "RCTPropsAnimatedNode.h"
#import <objc/runtime.h>
#import <React/RCTLog.h>
#import <React/RCTSurfacePresenterStub.h>
#import <React/RCTUIManager.h>
#import "RCTAnimationUtils.h"
#import "RCTStyleAnimatedNode.h"
#import "RCTValueAnimatedNode.h"
// TODO: Eventually we should just include RCTSurfacePresenter.h, but that pulls in all of fabric
// which doesn't compile in open source yet, so we mirror the protocol and duplicate the category
// here for now.
@protocol SyncViewUpdater <NSObject>
- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
@end
@implementation RCTBridge (SurfacePresenterShadow)
- (id<SyncViewUpdater>)surfacePresenter
{
return objc_getAssociatedObject(self, @selector(surfacePresenter));
}
@end
@implementation RCTPropsAnimatedNode

View File

@@ -8,12 +8,13 @@
#import <React/RCTBridgeModule.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTSurfacePresenterStub.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import <React/RCTUIManagerUtils.h>
#import "RCTValueAnimatedNode.h"
@interface RCTNativeAnimatedModule : RCTEventEmitter <RCTBridgeModule, RCTValueAnimatedNodeObserver, RCTEventDispatcherObserver, RCTUIManagerObserver>
@interface RCTNativeAnimatedModule : RCTEventEmitter <RCTBridgeModule, RCTValueAnimatedNodeObserver, RCTEventDispatcherObserver, RCTUIManagerObserver, RCTSurfacePresenterObserver>
@end

View File

@@ -28,6 +28,7 @@ RCT_EXPORT_MODULE();
[_nodesManager stopAnimationLoop];
[self.bridge.eventDispatcher removeDispatchObserver:self];
[self.bridge.uiManager.observerCoordinator removeObserver:self];
[self.bridge.surfacePresenter removeObserver:self];
}
- (dispatch_queue_t)methodQueue
@@ -48,7 +49,8 @@ RCT_EXPORT_MODULE();
_animIdIsManagedByFabric = [NSMutableDictionary new];
[bridge.eventDispatcher addDispatchObserver:self];
[bridge.uiManager.observerCoordinator addObserver:self]; // TODO: add fabric equivalent?
[bridge.uiManager.observerCoordinator addObserver:self];
[bridge.surfacePresenter addObserver:self];
}
#pragma mark -- API
@@ -225,9 +227,29 @@ RCT_EXPORT_METHOD(removeAnimatedEventFromView:(nonnull NSNumber *)viewTag
});
}
#pragma mark - RCTSurfacePresenterObserver
- (void)willMountComponentsWithRootTag:(NSInteger)rootTag
{
RCTAssertMainQueue();
for (AnimatedOperation operation in _preOperations) {
operation(self->_nodesManager);
}
_preOperations = [NSMutableArray new];
}
- (void)didMountComponentsWithRootTag:(NSInteger)rootTag
{
RCTAssertMainQueue();
for (AnimatedOperation operation in _operations) {
operation(self->_nodesManager);
}
_operations = [NSMutableArray new];
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillPerformMounting:(RCTUIManager *)uiManager // TODO: need fabric equivalent
- (void)uiManagerWillPerformMounting:(RCTUIManager *)uiManager
{
if (_preOperations.count == 0 && _operations.count == 0) {
return;

View File

@@ -19,6 +19,16 @@ NS_ASSUME_NONNULL_BEGIN
@class RCTFabricSurface;
@class RCTMountingManager;
@protocol RCTSurfacePresenterObserver <NSObject>
@optional
- (void)willMountComponentsWithRootTag:(ReactTag)rootTag;
- (void)didMountComponentsWithRootTag:(ReactTag)rootTag;
@end
/**
* Coordinates presenting of React Native Surfaces and represents application
* facing interface of running React Native core.
@@ -68,6 +78,10 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
- (void)addObserver:(id<RCTSurfacePresenterObserver>)observer;
- (void)removeObserver:(id<RCTSurfacePresenterObserver>)observer;
@end
@interface RCTSurfacePresenter (Deprecated)

View File

@@ -53,6 +53,8 @@ using namespace facebook::react;
RCTBridge *_bridge; // Unsafe. We are moving away from Bridge.
RCTBridge *_batchedBridge;
std::shared_ptr<const ReactNativeConfig> _reactNativeConfig;
std::mutex _observerListMutex;
NSMutableArray<id<RCTSurfacePresenterObserver>> *_observers;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge config:(std::shared_ptr<const ReactNativeConfig>)config
@@ -309,13 +311,29 @@ using namespace facebook::react;
[_mountingManager optimisticallyCreateComponentViewWithComponentHandle:componentHandle];
}
- (void)addObserver:(id<RCTSurfacePresenterObserver>)observer
{
std::lock_guard<std::mutex> lock(_observerListMutex);
[self->_observers addObject:observer];
}
- (void)removeObserver:(id<RCTSurfacePresenterObserver>)observer
{
std::lock_guard<std::mutex> lock(_observerListMutex);
[self->_observers removeObject:observer];
}
#pragma mark - RCTMountingManagerDelegate
- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)rootTag
{
RCTAssertMainQueue();
// Does nothing.
for (id<RCTSurfacePresenterObserver> observer in _observers) {
if ([observer respondsToSelector:@selector(willMountComponentsWithRootTag:)]) {
[observer willMountComponentsWithRootTag:rootTag];
}
}
}
- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag
@@ -331,6 +349,11 @@ using namespace facebook::react;
surface.view.rootView = (RCTSurfaceRootView *)rootComponentView;
}
}
for (id<RCTSurfacePresenterObserver> observer in _observers) {
if ([observer respondsToSelector:@selector(didMountComponentsWithRootTag:)]) {
[observer didMountComponentsWithRootTag:rootTag];
}
}
}
#pragma mark - Bridge events

View File

@@ -0,0 +1,46 @@
/**
* 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 <objc/runtime.h>
#import <React/RCTBridge.h>
NS_ASSUME_NONNULL_BEGIN
// TODO: Eventually this should go away and files should just include RCTSurfacePresenter.h, but
// that pulls in all of fabric which doesn't compile in open source yet, so we mirror the protocol
// and duplicate the category here for now.
@protocol RCTSurfacePresenterObserver <NSObject>
@optional
- (void)willMountComponentsWithRootTag:(NSInteger)rootTag;
- (void)didMountComponentsWithRootTag:(NSInteger)rootTag;
@end
@protocol RCTSurfacePresenterStub <NSObject>
- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
- (void)addObserver:(id<RCTSurfacePresenterObserver>)observer;
- (void)removeObserver:(id<RCTSurfacePresenterObserver>)observer;
@end
@implementation RCTBridge (RCTSurfacePresenterStub)
- (id<RCTSurfacePresenterStub>)surfacePresenter
{
return objc_getAssociatedObject(self, @selector(surfacePresenter));
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -834,6 +834,8 @@
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
589515E02231AD9C0036BDE0 /* RCTSurfacePresenterStub.h in Headers */ = {isa = PBXBuildFile; fileRef = 589515DF2231AD9C0036BDE0 /* RCTSurfacePresenterStub.h */; };
589515E12231ADE00036BDE0 /* RCTSurfacePresenterStub.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 589515DF2231AD9C0036BDE0 /* RCTSurfacePresenterStub.h */; };
590D7BFD1EBD458B00D8A370 /* RCTShadowView+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 590D7BFB1EBD458B00D8A370 /* RCTShadowView+Layout.h */; };
590D7BFE1EBD458B00D8A370 /* RCTShadowView+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 590D7BFB1EBD458B00D8A370 /* RCTShadowView+Layout.h */; };
590D7BFF1EBD458B00D8A370 /* RCTShadowView+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 590D7BFC1EBD458B00D8A370 /* RCTShadowView+Layout.m */; };
@@ -1557,6 +1559,7 @@
dstPath = include/React;
dstSubfolderSpec = 16;
files = (
589515E12231ADE00036BDE0 /* RCTSurfacePresenterStub.h in Copy Headers */,
39C50FF92046EACF00CEE534 /* RCTVersion.h in Copy Headers */,
591F78DE202ADB8F004A668C /* RCTLayout.h in Copy Headers */,
59EDBCBD1FDF4E43003573DE /* RCTScrollableProtocol.h in Copy Headers */,
@@ -2096,6 +2099,7 @@
58114A151AAE854800E7D092 /* RCTPickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPickerManager.m; sourceTree = "<group>"; };
58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAsyncLocalStorage.m; sourceTree = "<group>"; };
58114A4F1AAE93D500E7D092 /* RCTAsyncLocalStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAsyncLocalStorage.h; sourceTree = "<group>"; };
589515DF2231AD9C0036BDE0 /* RCTSurfacePresenterStub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSurfacePresenterStub.h; sourceTree = "<group>"; };
58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDatePickerManager.m; sourceTree = "<group>"; };
58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDatePickerManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
590D7BFB1EBD458B00D8A370 /* RCTShadowView+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTShadowView+Layout.h"; sourceTree = "<group>"; };
@@ -2499,6 +2503,7 @@
13B07FE01A69315300A75B9A /* Modules */ = {
isa = PBXGroup;
children = (
589515DF2231AD9C0036BDE0 /* RCTSurfacePresenterStub.h */,
E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */,
E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */,
13B07FE71A69327A00A75B9A /* RCTAlertManager.h */,
@@ -3496,6 +3501,7 @@
3D0E378A1F1CC40000DCAC9F /* RCTWebSocketModule.h in Headers */,
3D80DA621DF820620028D040 /* RCTAutoInsetsProtocol.h in Headers */,
C60128AB1F3D1258009DF9FF /* RCTCxxConvert.h in Headers */,
589515E02231AD9C0036BDE0 /* RCTSurfacePresenterStub.h in Headers */,
59EDBCAD1FDF4E0C003573DE /* RCTScrollContentView.h in Headers */,
59EDBCA71FDF4E0C003573DE /* RCTScrollableProtocol.h in Headers */,
591F78DC202ADB22004A668C /* RCTLayout.h in Headers */,