UNPKG

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