RCTScrollViewManager.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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 "RCTScrollViewManager.h"
  8. #import "RCTBridge.h"
  9. #import "RCTScrollView.h"
  10. #import "RCTShadowView.h"
  11. #import "RCTUIManager.h"
  12. @interface RCTScrollView (Private)
  13. - (NSArray<NSDictionary *> *)calculateChildFramesData;
  14. @end
  15. @implementation RCTConvert (UIScrollView)
  16. RCT_ENUM_CONVERTER(
  17. UIScrollViewKeyboardDismissMode,
  18. (@{
  19. @"none" : @(UIScrollViewKeyboardDismissModeNone),
  20. @"on-drag" : @(UIScrollViewKeyboardDismissModeOnDrag),
  21. @"interactive" : @(UIScrollViewKeyboardDismissModeInteractive),
  22. // Backwards compatibility
  23. @"onDrag" : @(UIScrollViewKeyboardDismissModeOnDrag),
  24. }),
  25. UIScrollViewKeyboardDismissModeNone,
  26. integerValue)
  27. RCT_ENUM_CONVERTER(
  28. UIScrollViewIndicatorStyle,
  29. (@{
  30. @"default" : @(UIScrollViewIndicatorStyleDefault),
  31. @"black" : @(UIScrollViewIndicatorStyleBlack),
  32. @"white" : @(UIScrollViewIndicatorStyleWhite),
  33. }),
  34. UIScrollViewIndicatorStyleDefault,
  35. integerValue)
  36. #pragma clang diagnostic push
  37. #pragma clang diagnostic ignored "-Wunguarded-availability-new"
  38. #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
  39. RCT_ENUM_CONVERTER(
  40. UIScrollViewContentInsetAdjustmentBehavior,
  41. (@{
  42. @"automatic" : @(UIScrollViewContentInsetAdjustmentAutomatic),
  43. @"scrollableAxes" : @(UIScrollViewContentInsetAdjustmentScrollableAxes),
  44. @"never" : @(UIScrollViewContentInsetAdjustmentNever),
  45. @"always" : @(UIScrollViewContentInsetAdjustmentAlways),
  46. }),
  47. UIScrollViewContentInsetAdjustmentNever,
  48. integerValue)
  49. #endif
  50. #pragma clang diagnostic pop
  51. @end
  52. @implementation RCTScrollViewManager
  53. RCT_EXPORT_MODULE()
  54. - (UIView *)view
  55. {
  56. return [[RCTScrollView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
  57. }
  58. RCT_EXPORT_VIEW_PROPERTY(alwaysBounceHorizontal, BOOL)
  59. RCT_EXPORT_VIEW_PROPERTY(alwaysBounceVertical, BOOL)
  60. RCT_EXPORT_VIEW_PROPERTY(bounces, BOOL)
  61. RCT_EXPORT_VIEW_PROPERTY(bouncesZoom, BOOL)
  62. RCT_EXPORT_VIEW_PROPERTY(canCancelContentTouches, BOOL)
  63. RCT_EXPORT_VIEW_PROPERTY(centerContent, BOOL)
  64. RCT_EXPORT_VIEW_PROPERTY(maintainVisibleContentPosition, NSDictionary)
  65. RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
  66. RCT_EXPORT_VIEW_PROPERTY(decelerationRate, CGFloat)
  67. RCT_EXPORT_VIEW_PROPERTY(directionalLockEnabled, BOOL)
  68. RCT_EXPORT_VIEW_PROPERTY(indicatorStyle, UIScrollViewIndicatorStyle)
  69. RCT_EXPORT_VIEW_PROPERTY(keyboardDismissMode, UIScrollViewKeyboardDismissMode)
  70. RCT_EXPORT_VIEW_PROPERTY(maximumZoomScale, CGFloat)
  71. RCT_EXPORT_VIEW_PROPERTY(minimumZoomScale, CGFloat)
  72. RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
  73. #if !TARGET_OS_TV
  74. RCT_EXPORT_VIEW_PROPERTY(pagingEnabled, BOOL)
  75. RCT_REMAP_VIEW_PROPERTY(pinchGestureEnabled, scrollView.pinchGestureEnabled, BOOL)
  76. RCT_EXPORT_VIEW_PROPERTY(scrollsToTop, BOOL)
  77. #endif
  78. RCT_EXPORT_VIEW_PROPERTY(showsHorizontalScrollIndicator, BOOL)
  79. RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
  80. RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
  81. RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
  82. RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
  83. RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
  84. RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL)
  85. RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
  86. RCT_EXPORT_VIEW_PROPERTY(disableIntervalMomentum, BOOL)
  87. RCT_EXPORT_VIEW_PROPERTY(snapToOffsets, NSArray<NSNumber *>)
  88. RCT_EXPORT_VIEW_PROPERTY(snapToStart, BOOL)
  89. RCT_EXPORT_VIEW_PROPERTY(snapToEnd, BOOL)
  90. RCT_EXPORT_VIEW_PROPERTY(snapToAlignment, NSString)
  91. RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffset, CGPoint)
  92. RCT_EXPORT_VIEW_PROPERTY(onScrollBeginDrag, RCTDirectEventBlock)
  93. RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
  94. RCT_EXPORT_VIEW_PROPERTY(onScrollToTop, RCTDirectEventBlock)
  95. RCT_EXPORT_VIEW_PROPERTY(onScrollEndDrag, RCTDirectEventBlock)
  96. RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollBegin, RCTDirectEventBlock)
  97. RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollEnd, RCTDirectEventBlock)
  98. RCT_EXPORT_VIEW_PROPERTY(DEPRECATED_sendUpdatedChildFrames, BOOL)
  99. RCT_EXPORT_VIEW_PROPERTY(inverted, BOOL)
  100. #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
  101. RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior)
  102. #endif
  103. // overflow is used both in css-layout as well as by react-native. In css-layout
  104. // we always want to treat overflow as scroll but depending on what the overflow
  105. // is set to from js we want to clip drawing or not. This piece of code ensures
  106. // that css-layout is always treating the contents of a scroll container as
  107. // overflow: 'scroll'.
  108. RCT_CUSTOM_SHADOW_PROPERTY(overflow, YGOverflow, RCTShadowView)
  109. {
  110. #pragma unused(json)
  111. view.overflow = YGOverflowScroll;
  112. }
  113. RCT_EXPORT_METHOD(getContentSize : (nonnull NSNumber *)reactTag callback : (RCTResponseSenderBlock)callback)
  114. {
  115. [self.bridge.uiManager
  116. addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
  117. RCTScrollView *view = viewRegistry[reactTag];
  118. if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
  119. RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
  120. return;
  121. }
  122. CGSize size = view.scrollView.contentSize;
  123. callback(@[ @{@"width" : @(size.width), @"height" : @(size.height)} ]);
  124. }];
  125. }
  126. RCT_EXPORT_METHOD(calculateChildFrames : (nonnull NSNumber *)reactTag callback : (RCTResponseSenderBlock)callback)
  127. {
  128. [self.bridge.uiManager
  129. addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
  130. RCTScrollView *view = viewRegistry[reactTag];
  131. if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
  132. RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
  133. return;
  134. }
  135. NSArray<NSDictionary *> *childFrames = [view calculateChildFramesData];
  136. if (childFrames) {
  137. callback(@[ childFrames ]);
  138. }
  139. }];
  140. }
  141. RCT_EXPORT_METHOD(scrollTo
  142. : (nonnull NSNumber *)reactTag offsetX
  143. : (CGFloat)x offsetY
  144. : (CGFloat)y animated
  145. : (BOOL)animated)
  146. {
  147. [self.bridge.uiManager
  148. addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
  149. UIView *view = viewRegistry[reactTag];
  150. if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
  151. [(id<RCTScrollableProtocol>)view scrollToOffset:(CGPoint){x, y} animated:animated];
  152. } else {
  153. RCTLogError(
  154. @"tried to scrollTo: on non-RCTScrollableProtocol view %@ "
  155. "with tag #%@",
  156. view,
  157. reactTag);
  158. }
  159. }];
  160. }
  161. RCT_EXPORT_METHOD(scrollToEnd : (nonnull NSNumber *)reactTag animated : (BOOL)animated)
  162. {
  163. [self.bridge.uiManager
  164. addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
  165. UIView *view = viewRegistry[reactTag];
  166. if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
  167. [(id<RCTScrollableProtocol>)view scrollToEnd:animated];
  168. } else {
  169. RCTLogError(
  170. @"tried to scrollTo: on non-RCTScrollableProtocol view %@ "
  171. "with tag #%@",
  172. view,
  173. reactTag);
  174. }
  175. }];
  176. }
  177. RCT_EXPORT_METHOD(zoomToRect : (nonnull NSNumber *)reactTag withRect : (CGRect)rect animated : (BOOL)animated)
  178. {
  179. [self.bridge.uiManager
  180. addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
  181. UIView *view = viewRegistry[reactTag];
  182. if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
  183. [(id<RCTScrollableProtocol>)view zoomToRect:rect animated:animated];
  184. } else {
  185. RCTLogError(
  186. @"tried to zoomToRect: on non-RCTScrollableProtocol view %@ "
  187. "with tag #%@",
  188. view,
  189. reactTag);
  190. }
  191. }];
  192. }
  193. RCT_EXPORT_METHOD(flashScrollIndicators : (nonnull NSNumber *)reactTag)
  194. {
  195. [self.bridge.uiManager
  196. addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
  197. RCTScrollView *view = viewRegistry[reactTag];
  198. if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
  199. RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
  200. return;
  201. }
  202. [view.scrollView flashScrollIndicators];
  203. }];
  204. }
  205. @end