RCTNativeAnimatedModule.mm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import <FBReactNativeSpec/FBReactNativeSpec.h>
  8. #import <React/RCTNativeAnimatedModule.h>
  9. #import <React/RCTNativeAnimatedNodesManager.h>
  10. #import <RCTTypeSafety/RCTConvertHelpers.h>
  11. #import "RCTAnimationPlugins.h"
  12. typedef void (^AnimatedOperation)(RCTNativeAnimatedNodesManager *nodesManager);
  13. @interface RCTNativeAnimatedModule() <NativeAnimatedModuleSpec>
  14. @end
  15. @implementation RCTNativeAnimatedModule
  16. {
  17. RCTNativeAnimatedNodesManager *_nodesManager;
  18. // Operations called after views have been updated.
  19. NSMutableArray<AnimatedOperation> *_operations;
  20. // Operations called before views have been updated.
  21. NSMutableArray<AnimatedOperation> *_preOperations;
  22. NSMutableDictionary<NSNumber *, NSNumber *> *_animIdIsManagedByFabric;
  23. }
  24. RCT_EXPORT_MODULE();
  25. - (void)invalidate
  26. {
  27. [_nodesManager stopAnimationLoop];
  28. [self.bridge.eventDispatcher removeDispatchObserver:self];
  29. [self.bridge.uiManager.observerCoordinator removeObserver:self];
  30. [self.bridge.surfacePresenter removeObserver:self];
  31. }
  32. - (dispatch_queue_t)methodQueue
  33. {
  34. // This module needs to be on the same queue as the UIManager to avoid
  35. // having to lock `_operations` and `_preOperations` since `uiManagerWillPerformMounting`
  36. // will be called from that queue.
  37. return RCTGetUIManagerQueue();
  38. }
  39. - (void)setBridge:(RCTBridge *)bridge
  40. {
  41. [super setBridge:bridge];
  42. _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge];
  43. _operations = [NSMutableArray new];
  44. _preOperations = [NSMutableArray new];
  45. _animIdIsManagedByFabric = [NSMutableDictionary new];
  46. [bridge.eventDispatcher addDispatchObserver:self];
  47. [bridge.uiManager.observerCoordinator addObserver:self];
  48. [bridge.surfacePresenter addObserver:self];
  49. }
  50. #pragma mark -- API
  51. RCT_EXPORT_METHOD(createAnimatedNode:(double)tag
  52. config:(NSDictionary<NSString *, id> *)config)
  53. {
  54. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  55. [nodesManager createAnimatedNode:[NSNumber numberWithDouble:tag] config:config];
  56. }];
  57. }
  58. RCT_EXPORT_METHOD(connectAnimatedNodes:(double)parentTag
  59. childTag:(double)childTag)
  60. {
  61. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  62. [nodesManager connectAnimatedNodes:[NSNumber numberWithDouble:parentTag] childTag:[NSNumber numberWithDouble:childTag]];
  63. }];
  64. }
  65. RCT_EXPORT_METHOD(disconnectAnimatedNodes:(double)parentTag
  66. childTag:(double)childTag)
  67. {
  68. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  69. [nodesManager disconnectAnimatedNodes:[NSNumber numberWithDouble:parentTag] childTag:[NSNumber numberWithDouble:childTag]];
  70. }];
  71. }
  72. RCT_EXPORT_METHOD(startAnimatingNode:(double)animationId
  73. nodeTag:(double)nodeTag
  74. config:(NSDictionary<NSString *, id> *)config
  75. endCallback:(RCTResponseSenderBlock)callBack)
  76. {
  77. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  78. [nodesManager startAnimatingNode:[NSNumber numberWithDouble:animationId] nodeTag:[NSNumber numberWithDouble:nodeTag] config:config endCallback:callBack];
  79. }];
  80. RCTExecuteOnMainQueue(^{
  81. if (![self->_nodesManager isNodeManagedByFabric:[NSNumber numberWithDouble:nodeTag]]) {
  82. return;
  83. }
  84. RCTExecuteOnUIManagerQueue(^{
  85. self->_animIdIsManagedByFabric[[NSNumber numberWithDouble:animationId]] = @YES;
  86. [self flushOperationQueues];
  87. });
  88. });
  89. }
  90. RCT_EXPORT_METHOD(stopAnimation:(double)animationId)
  91. {
  92. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  93. [nodesManager stopAnimation:[NSNumber numberWithDouble:animationId]];
  94. }];
  95. if ([_animIdIsManagedByFabric[[NSNumber numberWithDouble:animationId]] boolValue]) {
  96. [self flushOperationQueues];
  97. }
  98. }
  99. RCT_EXPORT_METHOD(setAnimatedNodeValue:(double)nodeTag
  100. value:(double)value)
  101. {
  102. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  103. [nodesManager setAnimatedNodeValue:[NSNumber numberWithDouble:nodeTag] value:[NSNumber numberWithDouble:value]];
  104. }];
  105. }
  106. RCT_EXPORT_METHOD(setAnimatedNodeOffset:(double)nodeTag
  107. offset:(double)offset)
  108. {
  109. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  110. [nodesManager setAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag] offset:[NSNumber numberWithDouble:offset]];
  111. }];
  112. }
  113. RCT_EXPORT_METHOD(flattenAnimatedNodeOffset:(double)nodeTag)
  114. {
  115. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  116. [nodesManager flattenAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]];
  117. }];
  118. }
  119. RCT_EXPORT_METHOD(extractAnimatedNodeOffset:(double)nodeTag)
  120. {
  121. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  122. [nodesManager extractAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]];
  123. }];
  124. }
  125. RCT_EXPORT_METHOD(connectAnimatedNodeToView:(double)nodeTag
  126. viewTag:(double)viewTag)
  127. {
  128. NSString *viewName = [self.bridge.uiManager viewNameForReactTag:[NSNumber numberWithDouble:viewTag]];
  129. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  130. [nodesManager connectAnimatedNodeToView:[NSNumber numberWithDouble:nodeTag] viewTag:[NSNumber numberWithDouble:viewTag] viewName:viewName];
  131. }];
  132. }
  133. RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView:(double)nodeTag
  134. viewTag:(double)viewTag)
  135. {
  136. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  137. [nodesManager disconnectAnimatedNodeFromView:[NSNumber numberWithDouble:nodeTag] viewTag:[NSNumber numberWithDouble:viewTag]];
  138. }];
  139. }
  140. RCT_EXPORT_METHOD(restoreDefaultValues:(double)nodeTag)
  141. {
  142. [self addPreOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  143. [nodesManager restoreDefaultValues:[NSNumber numberWithDouble:nodeTag]];
  144. }];
  145. }
  146. RCT_EXPORT_METHOD(dropAnimatedNode:(double)tag)
  147. {
  148. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  149. [nodesManager dropAnimatedNode:[NSNumber numberWithDouble:tag]];
  150. }];
  151. }
  152. RCT_EXPORT_METHOD(startListeningToAnimatedNodeValue:(double)tag)
  153. {
  154. __weak id<RCTValueAnimatedNodeObserver> valueObserver = self;
  155. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  156. [nodesManager startListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag] valueObserver:valueObserver];
  157. }];
  158. }
  159. RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(double)tag)
  160. {
  161. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  162. [nodesManager stopListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag]];
  163. }];
  164. }
  165. RCT_EXPORT_METHOD(addAnimatedEventToView:(double)viewTag
  166. eventName:(nonnull NSString *)eventName
  167. eventMapping:(JS::NativeAnimatedModule::EventMapping &)eventMapping)
  168. {
  169. NSMutableDictionary *eventMappingDict = [NSMutableDictionary new];
  170. eventMappingDict[@"nativeEventPath"] = RCTConvertVecToArray(eventMapping.nativeEventPath());
  171. if (eventMapping.animatedValueTag()) {
  172. eventMappingDict[@"animatedValueTag"] = @(*eventMapping.animatedValueTag());
  173. }
  174. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  175. [nodesManager addAnimatedEventToView:[NSNumber numberWithDouble:viewTag] eventName:eventName eventMapping:eventMappingDict];
  176. }];
  177. }
  178. RCT_EXPORT_METHOD(removeAnimatedEventFromView:(double)viewTag
  179. eventName:(nonnull NSString *)eventName
  180. animatedNodeTag:(double)animatedNodeTag)
  181. {
  182. [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
  183. [nodesManager removeAnimatedEventFromView:[NSNumber numberWithDouble:viewTag] eventName:eventName animatedNodeTag:[NSNumber numberWithDouble:animatedNodeTag]];
  184. }];
  185. }
  186. #pragma mark -- Batch handling
  187. - (void)addOperationBlock:(AnimatedOperation)operation
  188. {
  189. [_operations addObject:operation];
  190. }
  191. - (void)addPreOperationBlock:(AnimatedOperation)operation
  192. {
  193. [_preOperations addObject:operation];
  194. }
  195. - (void)flushOperationQueues
  196. {
  197. if (_preOperations.count == 0 && _operations.count == 0) {
  198. return;
  199. }
  200. NSArray<AnimatedOperation> *preOperations = _preOperations;
  201. NSArray<AnimatedOperation> *operations = _operations;
  202. _preOperations = [NSMutableArray new];
  203. _operations = [NSMutableArray new];
  204. RCTExecuteOnMainQueue(^{
  205. for (AnimatedOperation operation in preOperations) {
  206. operation(self->_nodesManager);
  207. }
  208. for (AnimatedOperation operation in operations) {
  209. operation(self->_nodesManager);
  210. }
  211. [self->_nodesManager updateAnimations];
  212. });
  213. }
  214. #pragma mark - RCTSurfacePresenterObserver
  215. - (void)willMountComponentsWithRootTag:(NSInteger)rootTag
  216. {
  217. RCTAssertMainQueue();
  218. RCTExecuteOnUIManagerQueue(^{
  219. NSArray<AnimatedOperation> *preOperations = self->_preOperations;
  220. self->_preOperations = [NSMutableArray new];
  221. RCTExecuteOnMainQueue(^{
  222. for (AnimatedOperation preOperation in preOperations) {
  223. preOperation(self->_nodesManager);
  224. }
  225. });
  226. });
  227. }
  228. - (void)didMountComponentsWithRootTag:(NSInteger)rootTag
  229. {
  230. RCTAssertMainQueue();
  231. RCTExecuteOnUIManagerQueue(^{
  232. NSArray<AnimatedOperation> *operations = self->_operations;
  233. self->_operations = [NSMutableArray new];
  234. RCTExecuteOnMainQueue(^{
  235. for (AnimatedOperation operation in operations) {
  236. operation(self->_nodesManager);
  237. }
  238. });
  239. });
  240. }
  241. #pragma mark - RCTUIManagerObserver
  242. - (void)uiManagerWillPerformMounting:(RCTUIManager *)uiManager
  243. {
  244. if (_preOperations.count == 0 && _operations.count == 0) {
  245. return;
  246. }
  247. NSArray<AnimatedOperation> *preOperations = _preOperations;
  248. NSArray<AnimatedOperation> *operations = _operations;
  249. _preOperations = [NSMutableArray new];
  250. _operations = [NSMutableArray new];
  251. [uiManager prependUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
  252. for (AnimatedOperation operation in preOperations) {
  253. operation(self->_nodesManager);
  254. }
  255. }];
  256. [uiManager addUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
  257. for (AnimatedOperation operation in operations) {
  258. operation(self->_nodesManager);
  259. }
  260. [self->_nodesManager updateAnimations];
  261. }];
  262. }
  263. #pragma mark -- Events
  264. - (NSArray<NSString *> *)supportedEvents
  265. {
  266. return @[@"onAnimatedValueUpdate"];
  267. }
  268. - (void)animatedNode:(RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value
  269. {
  270. [self sendEventWithName:@"onAnimatedValueUpdate"
  271. body:@{@"tag": node.nodeTag, @"value": @(value)}];
  272. }
  273. - (void)eventDispatcherWillDispatchEvent:(id<RCTEvent>)event
  274. {
  275. // Events can be dispatched from any queue so we have to make sure handleAnimatedEvent
  276. // is run from the main queue.
  277. RCTExecuteOnMainQueue(^{
  278. [self->_nodesManager handleAnimatedEvent:event];
  279. });
  280. }
  281. - (std::shared_ptr<facebook::react::TurboModule>)
  282. getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
  283. nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
  284. perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
  285. {
  286. return std::make_shared<facebook::react::NativeAnimatedModuleSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
  287. }
  288. @end
  289. Class RCTNativeAnimatedModuleCls(void) {
  290. return RCTNativeAnimatedModule.class;
  291. }