mirror of
https://github.com/status-im/react-native.git
synced 2025-01-10 09:35:48 +00:00
0a9b6bedb3
Summary: This fixes measuring of items in the main axis of a container. Previously items were in a lot of cases measured with UNSPECIFIED instead of AT_MOST. This was to support scrolling containers. The correct way to handle scrolling containers is to instead provide them with their own overflow value to activate this behavior. This is also similar to how the web works. This is a breaking change. Most of your layouts will continue to function as before however some of them might not. Typically this is due to having a `flex: 1` style where it is currently a no-op due to being measured with an undefined size but after this change it may collapse your component to take zero size due to the implicit `flexBasis: 0` now being correctly treated. Removing the bad `flex: 1` style or changing it to `flexGrow: 1` should solve most if not all layout issues your see after this diff. Reviewed By: majak Differential Revision: D3876927 fbshipit-source-id: 81ea1c9d6574dd4564a3333f1b3617cf84b4022f
165 lines
6.0 KiB
Objective-C
165 lines
6.0 KiB
Objective-C
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "RCTScrollViewManager.h"
|
|
|
|
#import "RCTBridge.h"
|
|
#import "RCTScrollView.h"
|
|
#import "RCTShadowView.h"
|
|
#import "RCTUIManager.h"
|
|
|
|
@interface RCTScrollView (Private)
|
|
|
|
- (NSArray<NSDictionary *> *)calculateChildFramesData;
|
|
|
|
@end
|
|
|
|
@implementation RCTConvert (UIScrollView)
|
|
|
|
RCT_ENUM_CONVERTER(UIScrollViewKeyboardDismissMode, (@{
|
|
@"none": @(UIScrollViewKeyboardDismissModeNone),
|
|
@"on-drag": @(UIScrollViewKeyboardDismissModeOnDrag),
|
|
@"interactive": @(UIScrollViewKeyboardDismissModeInteractive),
|
|
// Backwards compatibility
|
|
@"onDrag": @(UIScrollViewKeyboardDismissModeOnDrag),
|
|
}), UIScrollViewKeyboardDismissModeNone, integerValue)
|
|
|
|
RCT_ENUM_CONVERTER(UIScrollViewIndicatorStyle, (@{
|
|
@"default": @(UIScrollViewIndicatorStyleDefault),
|
|
@"black": @(UIScrollViewIndicatorStyleBlack),
|
|
@"white": @(UIScrollViewIndicatorStyleWhite),
|
|
}), UIScrollViewIndicatorStyleDefault, integerValue)
|
|
|
|
@end
|
|
|
|
@implementation RCTScrollViewManager
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
- (UIView *)view
|
|
{
|
|
return [[RCTScrollView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
|
|
}
|
|
|
|
RCT_EXPORT_VIEW_PROPERTY(alwaysBounceHorizontal, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(alwaysBounceVertical, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(bounces, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(bouncesZoom, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(canCancelContentTouches, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(centerContent, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(decelerationRate, CGFloat)
|
|
RCT_EXPORT_VIEW_PROPERTY(directionalLockEnabled, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(indicatorStyle, UIScrollViewIndicatorStyle)
|
|
RCT_EXPORT_VIEW_PROPERTY(keyboardDismissMode, UIScrollViewKeyboardDismissMode)
|
|
RCT_EXPORT_VIEW_PROPERTY(maximumZoomScale, CGFloat)
|
|
RCT_EXPORT_VIEW_PROPERTY(minimumZoomScale, CGFloat)
|
|
RCT_EXPORT_VIEW_PROPERTY(pagingEnabled, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(scrollsToTop, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(showsHorizontalScrollIndicator, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(stickyHeaderIndices, NSIndexSet)
|
|
RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
|
|
RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
|
|
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
|
|
RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
|
|
RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
|
|
RCT_EXPORT_VIEW_PROPERTY(snapToAlignment, NSString)
|
|
RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffset, CGPoint)
|
|
RCT_EXPORT_VIEW_PROPERTY(onScrollBeginDrag, RCTDirectEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onScrollEndDrag, RCTDirectEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollBegin, RCTDirectEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollEnd, RCTDirectEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onScrollAnimationEnd, RCTDirectEventBlock)
|
|
|
|
// overflow is used both in css-layout as well as by reac-native. In css-layout
|
|
// we always want to treat overflow as scroll but depending on what the overflow
|
|
// is set to from js we want to clip drawing or not. This piece of code ensures
|
|
// that css-layout is always treating the contents of a scroll container as
|
|
// overflow: 'scroll'.
|
|
RCT_CUSTOM_SHADOW_PROPERTY(overflow, CSSOverflow, RCTShadowView) {
|
|
view.overflow = CSSOverflowScroll;
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(getContentSize:(nonnull NSNumber *)reactTag
|
|
callback:(RCTResponseSenderBlock)callback)
|
|
{
|
|
[self.bridge.uiManager addUIBlock:
|
|
^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
|
|
|
|
RCTScrollView *view = viewRegistry[reactTag];
|
|
if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
|
|
RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
|
|
return;
|
|
}
|
|
|
|
CGSize size = view.scrollView.contentSize;
|
|
callback(@[@{
|
|
@"width" : @(size.width),
|
|
@"height" : @(size.height)
|
|
}]);
|
|
}];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(calculateChildFrames:(nonnull NSNumber *)reactTag
|
|
callback:(RCTResponseSenderBlock)callback)
|
|
{
|
|
[self.bridge.uiManager addUIBlock:
|
|
^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
|
|
|
|
RCTScrollView *view = viewRegistry[reactTag];
|
|
if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
|
|
RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
|
|
return;
|
|
}
|
|
|
|
NSArray<NSDictionary *> *childFrames = [view calculateChildFramesData];
|
|
if (childFrames) {
|
|
callback(@[childFrames]);
|
|
}
|
|
}];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(scrollTo:(nonnull NSNumber *)reactTag
|
|
offsetX:(CGFloat)x
|
|
offsetY:(CGFloat)y
|
|
animated:(BOOL)animated)
|
|
{
|
|
[self.bridge.uiManager addUIBlock:
|
|
^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
|
|
UIView *view = viewRegistry[reactTag];
|
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
|
[(id<RCTScrollableProtocol>)view scrollToOffset:(CGPoint){x, y} animated:animated];
|
|
} else {
|
|
RCTLogError(@"tried to scrollTo: on non-RCTScrollableProtocol view %@ "
|
|
"with tag #%@", view, reactTag);
|
|
}
|
|
}];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag
|
|
withRect:(CGRect)rect
|
|
animated:(BOOL)animated)
|
|
{
|
|
[self.bridge.uiManager addUIBlock:
|
|
^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
|
|
UIView *view = viewRegistry[reactTag];
|
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
|
[(id<RCTScrollableProtocol>)view zoomToRect:rect animated:animated];
|
|
} else {
|
|
RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ "
|
|
"with tag #%@", view, reactTag);
|
|
}
|
|
}];
|
|
}
|
|
|
|
@end
|