Simplifying mess with RCTRootViewSizeFlexibility
Summary: Now things look much more clear, I hope. This diff: * Introduces new property of `RCTRootShadowView` `availableSize` which represents exactly what we transmit to layout engine; * Illuminates conflict between logical `availableSize` and explicitly specified size of DOM node (current `size`); * Splits overcomplicated `setSize:forView:` method into two unrelated ones; * Changes actual values of `RCTRootViewSizeFlexibility` enum constants for simpler usage; * Completely removes `sizeFlexibility` concept from `RCTRootShadowView` (in favor of special values of `availableSize`); * Makes the code clearer finally. This is beginning of big effort to improve `RCTRootView` and co. Reviewed By: mmmulani Differential Revision: D4562834 fbshipit-source-id: f5baaf2859ea430d44645a6b5d35f222f15a668e
This commit is contained in:
Родитель
4a893ee071
Коммит
ba170ec78c
|
@ -22,9 +22,9 @@
|
||||||
*/
|
*/
|
||||||
typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
|
typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
|
||||||
RCTRootViewSizeFlexibilityNone = 0,
|
RCTRootViewSizeFlexibilityNone = 0,
|
||||||
RCTRootViewSizeFlexibilityWidth,
|
RCTRootViewSizeFlexibilityWidth = 1 << 0,
|
||||||
RCTRootViewSizeFlexibilityHeight,
|
RCTRootViewSizeFlexibilityHeight = 1 << 1,
|
||||||
RCTRootViewSizeFlexibilityWidthAndHeight,
|
RCTRootViewSizeFlexibilityWidthAndHeight = RCTRootViewSizeFlexibilityWidth | RCTRootViewSizeFlexibilityHeight,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -45,6 +45,7 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat
|
||||||
@property (nonatomic, readonly) BOOL contentHasAppeared;
|
@property (nonatomic, readonly) BOOL contentHasAppeared;
|
||||||
@property (nonatomic, readonly, strong) RCTTouchHandler *touchHandler;
|
@property (nonatomic, readonly, strong) RCTTouchHandler *touchHandler;
|
||||||
@property (nonatomic, assign) BOOL passThroughTouches;
|
@property (nonatomic, assign) BOOL passThroughTouches;
|
||||||
|
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
|
||||||
|
|
||||||
- (instancetype)initWithFrame:(CGRect)frame
|
- (instancetype)initWithFrame:(CGRect)frame
|
||||||
bridge:(RCTBridge *)bridge
|
bridge:(RCTBridge *)bridge
|
||||||
|
@ -281,8 +282,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||||
|
|
||||||
- (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
|
- (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
|
||||||
{
|
{
|
||||||
|
if (_sizeFlexibility == sizeFlexibility) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_sizeFlexibility = sizeFlexibility;
|
_sizeFlexibility = sizeFlexibility;
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
|
_contentView.sizeFlexibility = _sizeFlexibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
|
@ -383,9 +389,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||||
if ((self = [super initWithFrame:frame])) {
|
if ((self = [super initWithFrame:frame])) {
|
||||||
_bridge = bridge;
|
_bridge = bridge;
|
||||||
self.reactTag = reactTag;
|
self.reactTag = reactTag;
|
||||||
|
_sizeFlexibility = sizeFlexibility;
|
||||||
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
|
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
|
||||||
[_touchHandler attachToView:self];
|
[_touchHandler attachToView:self];
|
||||||
[_bridge.uiManager registerRootView:self withSizeFlexibility:sizeFlexibility];
|
[_bridge.uiManager registerRootView:self];
|
||||||
self.layer.backgroundColor = NULL;
|
self.layer.backgroundColor = NULL;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
@ -394,6 +401,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||||
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame:(CGRect)frame)
|
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame:(CGRect)frame)
|
||||||
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder:(nonnull NSCoder *)aDecoder)
|
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder:(nonnull NSCoder *)aDecoder)
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[super layoutSubviews];
|
||||||
|
[self updateAvailableSize];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
||||||
{
|
{
|
||||||
[super insertReactSubview:subview atIndex:atIndex];
|
[super insertReactSubview:subview atIndex:atIndex];
|
||||||
|
@ -407,12 +420,30 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder:(nonnull NSCoder *)aDecoder)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrame:(CGRect)frame
|
- (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
|
||||||
{
|
{
|
||||||
super.frame = frame;
|
if (_sizeFlexibility == sizeFlexibility) {
|
||||||
if (self.reactTag && _bridge.isValid) {
|
return;
|
||||||
[_bridge.uiManager setSize:frame.size forView:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_sizeFlexibility = sizeFlexibility;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateAvailableSize
|
||||||
|
{
|
||||||
|
if (!self.reactTag || !_bridge.isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGSize size = self.bounds.size;
|
||||||
|
CGSize availableSize =
|
||||||
|
CGSizeMake(
|
||||||
|
_sizeFlexibility & RCTRootViewSizeFlexibilityWidth ? INFINITY : size.width,
|
||||||
|
_sizeFlexibility & RCTRootViewSizeFlexibilityHeight ? INFINITY : size.height
|
||||||
|
);
|
||||||
|
|
||||||
|
[_bridge.uiManager setAvailableSize:availableSize forRootView:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundColor:(UIColor *)backgroundColor
|
- (void)setBackgroundColor:(UIColor *)backgroundColor
|
||||||
|
|
|
@ -58,7 +58,7 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
|
||||||
/**
|
/**
|
||||||
* Register a root view with the RCTUIManager.
|
* Register a root view with the RCTUIManager.
|
||||||
*/
|
*/
|
||||||
- (void)registerRootView:(UIView *)rootView withSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility;
|
- (void)registerRootView:(UIView *)rootView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the view name associated with a reactTag.
|
* Gets the view name associated with a reactTag.
|
||||||
|
@ -70,6 +70,15 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
|
||||||
*/
|
*/
|
||||||
- (UIView *)viewForReactTag:(NSNumber *)reactTag;
|
- (UIView *)viewForReactTag:(NSNumber *)reactTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the available size (`availableSize` property) for a root view.
|
||||||
|
* This might be used in response to changes in external layout constraints.
|
||||||
|
* This value will be directly trasmitted to layout engine and defines how big viewport is;
|
||||||
|
* this value does not affect root node size style properties.
|
||||||
|
* Can be considered as something similar to `setSize:forView:` but applicable only for root view.
|
||||||
|
*/
|
||||||
|
- (void)setAvailableSize:(CGSize)availableSize forRootView:(UIView *)rootView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the size of a view. This might be in response to a screen rotation
|
* Set the size of a view. This might be in response to a screen rotation
|
||||||
* or some other layout event outside of the React-managed view hierarchy.
|
* or some other layout event outside of the React-managed view hierarchy.
|
||||||
|
@ -149,6 +158,14 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
|
||||||
- (void)setFrame:(CGRect)frame forView:(UIView *)view
|
- (void)setFrame:(CGRect)frame forView:(UIView *)view
|
||||||
__deprecated_msg("Use `setSize:forView:` or `setIntrinsicContentSize:forView:` instead.");
|
__deprecated_msg("Use `setSize:forView:` or `setIntrinsicContentSize:forView:` instead.");
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is deprecated and will be removed in next releases.
|
||||||
|
* Use `registerRootView:` instead. There is no need to specify `sizeFlexibility` anymore.
|
||||||
|
*/
|
||||||
|
- (void)registerRootView:(UIView *)rootView withSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
|
||||||
|
__deprecated_msg("Use `registerRootView:` instead.");
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -376,7 +376,7 @@ dispatch_queue_t RCTGetUIManagerQueue(void)
|
||||||
return RCTGetUIManagerQueue();
|
return RCTGetUIManagerQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)registerRootView:(UIView *)rootView withSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
|
- (void)registerRootView:(UIView *)rootView
|
||||||
{
|
{
|
||||||
RCTAssertMainQueue();
|
RCTAssertMainQueue();
|
||||||
|
|
||||||
|
@ -390,7 +390,6 @@ dispatch_queue_t RCTGetUIManagerQueue(void)
|
||||||
|
|
||||||
// Register view
|
// Register view
|
||||||
_viewRegistry[reactTag] = rootView;
|
_viewRegistry[reactTag] = rootView;
|
||||||
CGSize size = rootView.bounds.size;
|
|
||||||
|
|
||||||
// Register shadow view
|
// Register shadow view
|
||||||
dispatch_async(RCTGetUIManagerQueue(), ^{
|
dispatch_async(RCTGetUIManagerQueue(), ^{
|
||||||
|
@ -400,10 +399,8 @@ dispatch_queue_t RCTGetUIManagerQueue(void)
|
||||||
|
|
||||||
RCTRootShadowView *shadowView = [RCTRootShadowView new];
|
RCTRootShadowView *shadowView = [RCTRootShadowView new];
|
||||||
shadowView.reactTag = reactTag;
|
shadowView.reactTag = reactTag;
|
||||||
shadowView.size = size;
|
|
||||||
shadowView.backgroundColor = rootView.backgroundColor;
|
shadowView.backgroundColor = rootView.backgroundColor;
|
||||||
shadowView.viewName = NSStringFromClass([rootView class]);
|
shadowView.viewName = NSStringFromClass([rootView class]);
|
||||||
shadowView.sizeFlexibility = sizeFlexibility;
|
|
||||||
self->_shadowViewRegistry[shadowView.reactTag] = shadowView;
|
self->_shadowViewRegistry[shadowView.reactTag] = shadowView;
|
||||||
[self->_rootViewTags addObject:reactTag];
|
[self->_rootViewTags addObject:reactTag];
|
||||||
});
|
});
|
||||||
|
@ -425,44 +422,39 @@ dispatch_queue_t RCTGetUIManagerQueue(void)
|
||||||
return _viewRegistry[reactTag];
|
return _viewRegistry[reactTag];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setAvailableSize:(CGSize)availableSize forRootView:(UIView *)rootView
|
||||||
|
{
|
||||||
|
RCTAssertMainQueue();
|
||||||
|
NSNumber *reactTag = rootView.reactTag;
|
||||||
|
dispatch_async(RCTGetUIManagerQueue(), ^{
|
||||||
|
RCTRootShadowView *shadowView = (RCTRootShadowView *)self->_shadowViewRegistry[reactTag];
|
||||||
|
RCTAssert(shadowView != nil, @"Could not locate shadow view with tag #%@", reactTag);
|
||||||
|
RCTAssert([shadowView isKindOfClass:[RCTRootShadowView class]], @"Located shadow view (with tag #%@) is actually not root view.", reactTag);
|
||||||
|
|
||||||
|
if (CGSizeEqualToSize(availableSize, shadowView.availableSize)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowView.availableSize = availableSize;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setSize:(CGSize)size forView:(UIView *)view
|
- (void)setSize:(CGSize)size forView:(UIView *)view
|
||||||
{
|
{
|
||||||
RCTAssertMainQueue();
|
RCTAssertMainQueue();
|
||||||
|
|
||||||
// The following variable has no meaning if the view is not a react root view
|
|
||||||
RCTRootViewSizeFlexibility sizeFlexibility = RCTRootViewSizeFlexibilityNone;
|
|
||||||
|
|
||||||
if (RCTIsReactRootView(view.reactTag)) {
|
|
||||||
RCTRootView *rootView = (RCTRootView *)[view superview];
|
|
||||||
if (rootView != nil) {
|
|
||||||
sizeFlexibility = rootView.sizeFlexibility;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NSNumber *reactTag = view.reactTag;
|
NSNumber *reactTag = view.reactTag;
|
||||||
dispatch_async(RCTGetUIManagerQueue(), ^{
|
dispatch_async(RCTGetUIManagerQueue(), ^{
|
||||||
RCTShadowView *shadowView = self->_shadowViewRegistry[reactTag];
|
RCTShadowView *shadowView = self->_shadowViewRegistry[reactTag];
|
||||||
RCTAssert(shadowView != nil, @"Could not locate shadow view with tag #%@", reactTag);
|
RCTAssert(shadowView != nil, @"Could not locate shadow view with tag #%@", reactTag);
|
||||||
|
|
||||||
BOOL needsLayout = NO;
|
if (CGSizeEqualToSize(size, shadowView.size)) {
|
||||||
if (!CGSizeEqualToSize(size, shadowView.size)) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
shadowView.size = size;
|
shadowView.size = size;
|
||||||
needsLayout = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger re-layout when size flexibility changes, as the root view might grow or
|
|
||||||
// shrink in the flexible dimensions.
|
|
||||||
if (RCTIsReactRootView(reactTag)) {
|
|
||||||
RCTRootShadowView *rootShadowView = (RCTRootShadowView *)shadowView;
|
|
||||||
if (rootShadowView.sizeFlexibility != sizeFlexibility) {
|
|
||||||
rootShadowView.sizeFlexibility = sizeFlexibility;
|
|
||||||
needsLayout = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsLayout) {
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1652,6 +1644,12 @@ static UIView *_jsResponder;
|
||||||
|
|
||||||
@implementation RCTUIManager (Deprecated)
|
@implementation RCTUIManager (Deprecated)
|
||||||
|
|
||||||
|
- (void)registerRootView:(UIView *)rootView withSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
|
||||||
|
{
|
||||||
|
RCTLogWarn(@"Calling of `[-RCTUIManager registerRootView:withSizeFlexibility:]` which is deprecated.");
|
||||||
|
[self registerRootView:rootView];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setFrame:(CGRect)frame forView:(UIView *)view
|
- (void)setFrame:(CGRect)frame forView:(UIView *)view
|
||||||
{
|
{
|
||||||
RCTLogWarn(@"Calling of `[-RCTUIManager setFrame:forView:]` which is deprecated.");
|
RCTLogWarn(@"Calling of `[-RCTUIManager setFrame:forView:]` which is deprecated.");
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
@interface RCTRootShadowView : RCTShadowView
|
@interface RCTRootShadowView : RCTShadowView
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size flexibility type used to find size constraints.
|
* Available size to layout all views.
|
||||||
* Default to RCTRootViewSizeFlexibilityNone
|
* Defaults to {INFINITY, INFINITY}
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
|
@property (nonatomic, assign) CGSize availableSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout direction (LTR or RTL) inherited from native environment and
|
* Layout direction (LTR or RTL) inherited from native environment and
|
||||||
|
|
|
@ -22,33 +22,18 @@
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_baseDirection = [[RCTI18nUtil sharedInstance] isRTL] ? YGDirectionRTL : YGDirectionLTR;
|
_baseDirection = [[RCTI18nUtil sharedInstance] isRTL] ? YGDirectionRTL : YGDirectionLTR;
|
||||||
|
_availableSize = CGSizeMake(INFINITY, INFINITY);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applySizeConstraints
|
|
||||||
{
|
|
||||||
switch (_sizeFlexibility) {
|
|
||||||
case RCTRootViewSizeFlexibilityNone:
|
|
||||||
break;
|
|
||||||
case RCTRootViewSizeFlexibilityWidth:
|
|
||||||
YGNodeStyleSetWidth(self.cssNode, YGUndefined);
|
|
||||||
break;
|
|
||||||
case RCTRootViewSizeFlexibilityHeight:
|
|
||||||
YGNodeStyleSetHeight(self.cssNode, YGUndefined);
|
|
||||||
break;
|
|
||||||
case RCTRootViewSizeFlexibilityWidthAndHeight:
|
|
||||||
YGNodeStyleSetWidth(self.cssNode, YGUndefined);
|
|
||||||
YGNodeStyleSetHeight(self.cssNode, YGUndefined);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSet<RCTShadowView *> *)collectViewsWithUpdatedFrames
|
- (NSSet<RCTShadowView *> *)collectViewsWithUpdatedFrames
|
||||||
{
|
{
|
||||||
[self applySizeConstraints];
|
// Treating `INFINITY` as `YGUndefined` (which equals `NAN`).
|
||||||
|
float availableWidth = _availableSize.width == INFINITY ? YGUndefined : _availableSize.width;
|
||||||
|
float availableHeight = _availableSize.height == INFINITY ? YGUndefined : _availableSize.height;
|
||||||
|
|
||||||
YGNodeCalculateLayout(self.cssNode, YGUndefined, YGUndefined, _baseDirection);
|
YGNodeCalculateLayout(self.cssNode, availableWidth, availableHeight, _baseDirection);
|
||||||
|
|
||||||
NSMutableSet<RCTShadowView *> *viewsWithNewFrame = [NSMutableSet set];
|
NSMutableSet<RCTShadowView *> *viewsWithNewFrame = [NSMutableSet set];
|
||||||
[self applyLayoutNode:self.cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:CGPointZero];
|
[self applyLayoutNode:self.cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:CGPointZero];
|
||||||
|
|
Загрузка…
Ссылка в новой задаче