RCTPropsAnimatedNode.m 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 <React/RCTPropsAnimatedNode.h>
  8. #import <React/RCTLog.h>
  9. #import <React/RCTSurfacePresenterStub.h>
  10. #import <React/RCTUIManager.h>
  11. #import <React/RCTAnimationUtils.h>
  12. #import <React/RCTStyleAnimatedNode.h>
  13. #import <React/RCTValueAnimatedNode.h>
  14. @implementation RCTPropsAnimatedNode
  15. {
  16. NSNumber *_connectedViewTag;
  17. NSNumber *_rootTag;
  18. NSString *_connectedViewName;
  19. __weak RCTBridge *_bridge;
  20. NSMutableDictionary<NSString *, NSObject *> *_propsDictionary; // TODO: use RawProps or folly::dynamic directly
  21. BOOL _managedByFabric;
  22. }
  23. - (instancetype)initWithTag:(NSNumber *)tag
  24. config:(NSDictionary<NSString *, id> *)config
  25. {
  26. if (self = [super initWithTag:tag config:config]) {
  27. _propsDictionary = [NSMutableDictionary new];
  28. }
  29. return self;
  30. }
  31. - (BOOL)isManagedByFabric
  32. {
  33. return _managedByFabric;
  34. }
  35. - (void)connectToView:(NSNumber *)viewTag
  36. viewName:(NSString *)viewName
  37. bridge:(RCTBridge *)bridge
  38. {
  39. _bridge = bridge;
  40. _connectedViewTag = viewTag;
  41. _connectedViewName = viewName;
  42. _managedByFabric = RCTUIManagerTypeForTagIsFabric(viewTag);
  43. _rootTag = nil;
  44. }
  45. - (void)disconnectFromView:(NSNumber *)viewTag
  46. {
  47. _bridge = nil;
  48. _connectedViewTag = nil;
  49. _connectedViewName = nil;
  50. _managedByFabric = NO;
  51. _rootTag = nil;
  52. }
  53. - (void)updateView
  54. {
  55. if (_managedByFabric) {
  56. [_bridge.surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag
  57. props:_propsDictionary];
  58. } else {
  59. [_bridge.uiManager synchronouslyUpdateViewOnUIThread:_connectedViewTag
  60. viewName:_connectedViewName
  61. props:_propsDictionary];
  62. }
  63. }
  64. - (void)restoreDefaultValues
  65. {
  66. // Restore the default value for all props that were modified by this node.
  67. for (NSString *key in _propsDictionary.allKeys) {
  68. _propsDictionary[key] = [NSNull null];
  69. }
  70. if (_propsDictionary.count) {
  71. [self updateView];
  72. }
  73. }
  74. - (NSString *)propertyNameForParentTag:(NSNumber *)parentTag
  75. {
  76. __block NSString *propertyName;
  77. [self.config[@"props"] enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull property, NSNumber *_Nonnull tag, BOOL *_Nonnull stop) {
  78. if ([tag isEqualToNumber:parentTag]) {
  79. propertyName = property;
  80. *stop = YES;
  81. }
  82. }];
  83. return propertyName;
  84. }
  85. - (void)performUpdate
  86. {
  87. [super performUpdate];
  88. // Since we are updating nodes after detaching them from views there is a time where it's
  89. // possible that the view was disconnected and still receive an update, this is normal and we can
  90. // simply skip that update.
  91. if (!_connectedViewTag) {
  92. return;
  93. }
  94. for (NSNumber *parentTag in self.parentNodes.keyEnumerator) {
  95. RCTAnimatedNode *parentNode = [self.parentNodes objectForKey:parentTag];
  96. if ([parentNode isKindOfClass:[RCTStyleAnimatedNode class]]) {
  97. [self->_propsDictionary addEntriesFromDictionary:[(RCTStyleAnimatedNode *)parentNode propsDictionary]];
  98. } else if ([parentNode isKindOfClass:[RCTValueAnimatedNode class]]) {
  99. NSString *property = [self propertyNameForParentTag:parentTag];
  100. id animatedObject = [(RCTValueAnimatedNode *)parentNode animatedObject];
  101. if (animatedObject) {
  102. self->_propsDictionary[property] = animatedObject;
  103. } else {
  104. CGFloat value = [(RCTValueAnimatedNode *)parentNode value];
  105. self->_propsDictionary[property] = @(value);
  106. }
  107. }
  108. }
  109. if (_propsDictionary.count) {
  110. [self updateView];
  111. }
  112. }
  113. @end