Files
Schnappix/node_modules/react-native-reanimated/apple/reanimated/apple/REANodesManager.mm
T

155 lines
3.7 KiB
Plaintext

#import <reanimated/apple/REAAssertJavaScriptQueue.h>
#import <reanimated/apple/REAAssertTurboModuleManagerQueue.h>
#import <reanimated/apple/REANodesManager.h>
#import <React/RCTUtils.h>
@implementation REANodesManager {
READisplayLink *_displayLink;
NSMutableArray<REAOnAnimationCallback> *_onAnimationCallbacks;
REAEventHandler _eventHandler;
REAPerformOperations _performOperations;
}
- (READisplayLink *)getDisplayLink
{
RCTAssertMainQueue();
if (!_displayLink) {
_displayLink = [READisplayLink displayLinkWithTarget:self selector:@selector(onAnimationFrame:)];
#if !TARGET_OS_OSX
_displayLink.preferredFramesPerSecond = 120; // will fallback to 60 fps for devices without Pro Motion display
#endif // TARGET_OS_OSX
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
return _displayLink;
}
- (void)useDisplayLinkOnMainQueue:(CADisplayLinkOperation)displayLinkOperation
{
// This method is called on the JavaScript queue during initialization or on the ShadowQueue during invalidation.
react_native_assert(REAIsJavaScriptQueue() || REAIsTurboModuleManagerQueue());
__weak __typeof__(self) weakSelf = self;
RCTExecuteOnMainQueue(^{
__typeof__(self) strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
displayLinkOperation([strongSelf getDisplayLink]);
});
}
- (nonnull instancetype)init
{
REAAssertJavaScriptQueue();
if ((self = [super init])) {
_onAnimationCallbacks = [NSMutableArray new];
_eventHandler = ^(id<RCTEvent> event) {
// no-op
};
}
[self useDisplayLinkOnMainQueue:^(READisplayLink *displayLink) {
[displayLink setPaused:YES];
}];
return self;
}
- (void)invalidate
{
REAAssertTurboModuleManagerQueue();
_eventHandler = nil;
[self useDisplayLinkOnMainQueue:^(READisplayLink *displayLink) {
[displayLink invalidate];
}];
}
- (void)postOnAnimation:(REAOnAnimationCallback)clb
{
RCTAssertMainQueue();
[_onAnimationCallbacks addObject:clb];
[self startUpdatingOnAnimationFrame];
}
- (void)registerEventHandler:(REAEventHandler)eventHandler
{
REAAssertJavaScriptQueue();
_eventHandler = eventHandler;
}
- (void)registerPerformOperations:(REAPerformOperations)performOperations
{
REAAssertJavaScriptQueue();
_performOperations = performOperations;
}
- (void)startUpdatingOnAnimationFrame
{
RCTAssertMainQueue();
[[self getDisplayLink] setPaused:NO];
}
- (void)stopUpdatingOnAnimationFrame
{
RCTAssertMainQueue();
[[self getDisplayLink] setPaused:YES];
}
- (void)onAnimationFrame:(READisplayLink *)displayLink
{
RCTAssertMainQueue();
NSArray<REAOnAnimationCallback> *callbacks = _onAnimationCallbacks;
_onAnimationCallbacks = [NSMutableArray new];
// When one of the callbacks would postOnAnimation callback we don't want
// to process it until the next frame. This is why we cpy the array before
// we iterate over it
for (REAOnAnimationCallback block in callbacks) {
block(displayLink);
}
[self performOperations];
if (_onAnimationCallbacks.count == 0) {
[self stopUpdatingOnAnimationFrame];
}
}
- (void)performOperations
{
RCTAssertMainQueue();
_performOperations(); // calls ReanimatedModuleProxy::performOperations
}
- (void)dispatchEvent:(id<RCTEvent>)event
{
RCTAssertMainQueue();
__weak REAEventHandler eventHandler = _eventHandler;
__weak __typeof__(self) weakSelf = self;
RCTExecuteOnMainQueue(^void() {
__typeof__(self) strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
if (eventHandler == nil) {
return;
}
eventHandler(event);
[strongSelf performOperations];
});
}
- (void)maybeFlushUIUpdatesQueue
{
RCTAssertMainQueue();
if ([[self getDisplayLink] isPaused]) {
[self performOperations];
}
}
@end