From 9dccff0eda5002b49d7ff5ac45091457e5197c06 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 27 Feb 2017 10:47:27 -0800 Subject: [PATCH] Better support of UIKit layout stuff for RCTRootView an co. Summary: Now RCTRootView is much more reliable citizen of UIKit, it got: * Implemented `sizeThatFits:`; * Implemented `instrinsicContentSize`; * Notifying superview via `setNeedsLayout` about changed size. All it make possible painless integration of ReactNative-powered widgets inside existing native apps. Reviewed By: javache Differential Revision: D4577890 fbshipit-source-id: 9897cb002c9d658a97fd436240c2ac947ba2084b --- React/Base/RCTRootView.m | 46 ++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index bd20f0ba97..0b5e5dbb6b 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -46,7 +46,6 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat NSString *_moduleName; NSDictionary *_launchOptions; RCTRootContentView *_contentView; - BOOL _passThroughTouches; } @@ -60,8 +59,7 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTRootView init]", nil); - if ((self = [super initWithFrame:CGRectZero])) { - + if (self = [super initWithFrame:CGRectZero]) { self.backgroundColor = [UIColor whiteColor]; _bridge = bridge; @@ -95,7 +93,7 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat #endif if (!_bridge.loading) { - [self bundleFinishedLoading:[_bridge batchedBridge]]; + [self bundleFinishedLoading:([_bridge batchedBridge] ?: _bridge)]; } [self showLoadingView]; @@ -137,6 +135,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) _contentView.backgroundColor = backgroundColor; } +#pragma mark - passThroughTouches + - (BOOL)passThroughTouches { return _contentView.passThroughTouches; @@ -148,6 +148,26 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) _contentView.passThroughTouches = passThroughTouches; } +#pragma mark - Layout + +- (CGSize)sizeThatFits:(CGSize)size +{ + return CGSizeMake( + _sizeFlexibility & RCTRootViewSizeFlexibilityWidth ? MIN(_intrinsicSize.width, size.width) : size.width, + _sizeFlexibility & RCTRootViewSizeFlexibilityHeight ? MIN(_intrinsicSize.height, size.height) : size.height + ); +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + _contentView.frame = self.bounds; + _loadingView.center = (CGPoint){ + CGRectGetMidX(self.bounds), + CGRectGetMidY(self.bounds) + }; +} + - (UIViewController *)reactViewController { return _reactViewController ?: [super reactViewController]; @@ -278,16 +298,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) _contentView.sizeFlexibility = _sizeFlexibility; } -- (void)layoutSubviews -{ - [super layoutSubviews]; - _contentView.frame = self.bounds; - _loadingView.center = (CGPoint){ - CGRectGetMidX(self.bounds), - CGRectGetMidY(self.bounds) - }; -} - - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // The root view itself should never receive touches @@ -323,6 +333,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) _intrinsicSize = intrinsicSize; + [self invalidateIntrinsicContentSize]; + [self.superview setNeedsLayout]; + // Don't notify the delegate if the content remains invisible or its size has not changed if (bothSizesHaveAZeroDimension || sizesAreEqual) { return; @@ -331,6 +344,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) [_delegate rootViewDidChangeIntrinsicSize:self]; } +- (CGSize)intrinsicContentSize +{ + return _intrinsicSize; +} + - (void)contentViewInvalidated { [_contentView removeFromSuperview];