Skip to content

Commit 46803f0

Browse files
Pawel Sienkowskifacebook-github-bot-7
authored andcommitted
Size flexibility modes for RCTRootView
Reviewed By: javache Differential Revision: D2526355 fb-gh-sync-id: 095a43bc01f883fdfdad3a086a35682c20c05597
1 parent 3a92f20 commit 46803f0

6 files changed

Lines changed: 77 additions & 11 deletions

File tree

Libraries/ReactIOS/renderApplication.ios.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,7 @@ function renderApplication<D, P, S>(
8787

8888
var styles = StyleSheet.create({
8989
appContainer: {
90-
position: 'absolute',
91-
left: 0,
92-
top: 0,
93-
right: 0,
94-
bottom: 0,
90+
flex: 1,
9591
},
9692
});
9793

React/Base/RCTRootView.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@
1111

1212
#import "RCTBridge.h"
1313

14+
/**
15+
* This enum is used to define size flexibility type of the root view.
16+
* If a dimension is flexible, the view will recalculate that dimension
17+
* so the content fits. Recalculations are performed when the root's frame,
18+
* size flexibility mode or content size changes. After a recalculation,
19+
* TODO:<DelegateName> will be called with the new size passed as an argument.
20+
*/
21+
typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
22+
RCTRootViewSizeFlexibilityNone = 0,
23+
RCTRootViewSizeFlexibilityWidth,
24+
RCTRootViewSizeFlexibilityHeight,
25+
RCTRootViewSizeFlexibilityWidthAndHeight,
26+
};
27+
1428
/**
1529
* This notification is sent when the first subviews are added to the root view
1630
* after the application has loaded. This is used to hide the `loadingView`, and
@@ -71,6 +85,11 @@ extern NSString *const RCTContentDidAppearNotification;
7185
*/
7286
@property (nonatomic, strong) Class executorClass;
7387

88+
/**
89+
* The size flexibility mode of the root view.
90+
*/
91+
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
92+
7493
/**
7594
* The backing view controller of the root view.
7695
*/

React/Base/RCTRootView.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
7272
_initialProperties = [initialProperties copy];
7373
_loadingViewFadeDelay = 0.25;
7474
_loadingViewFadeDuration = 0.25;
75+
_sizeFlexibility = RCTRootViewSizeFlexibilityNone;
7576

7677
[[NSNotificationCenter defaultCenter] addObserver:self
7778
selector:@selector(javaScriptDidLoad:)
@@ -189,6 +190,12 @@ - (void)bundleFinishedLoading:(RCTBridge *)bridge
189190
args:@[moduleName, appParameters]];
190191
}
191192

193+
- (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
194+
{
195+
_sizeFlexibility = sizeFlexibility;
196+
[self setNeedsLayout];
197+
}
198+
192199
- (void)layoutSubviews
193200
{
194201
[super layoutSubviews];

React/Modules/RCTUIManager.m

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,26 @@ - (void)setFrame:(CGRect)frame forView:(UIView *)view
347347
{
348348
RCTAssertMainThread();
349349

350+
// The following variables have no meaning if the view is not a react root view
351+
RCTRootView *rootView = (RCTRootView *)[view superview];
352+
RCTRootViewSizeFlexibility sizeFlexibility = rootView != nil ? rootView.sizeFlexibility : RCTRootViewSizeFlexibilityNone;
353+
350354
NSNumber *reactTag = view.reactTag;
351355
dispatch_async(_shadowQueue, ^{
352356
RCTShadowView *rootShadowView = _shadowViewRegistry[reactTag];
353357
RCTAssert(rootShadowView != nil, @"Could not locate root view with tag #%@", reactTag);
354-
rootShadowView.frame = frame;
358+
359+
if (RCTIsReactRootView(reactTag)) {
360+
if (CGRectEqualToRect(frame, rootShadowView.frame) && rootShadowView.sizeFlexibility == sizeFlexibility) {
361+
// This is to prevent infinite recursion when the frame update is trigerred by TODO(8608567):<DelegateName>
362+
return;
363+
}
364+
rootShadowView.frame = frame;
365+
rootShadowView.sizeFlexibility = sizeFlexibility;
366+
} else {
367+
rootShadowView.frame = frame;
368+
}
369+
355370
[rootShadowView updateLayout];
356371

357372
[self batchDidComplete];
@@ -437,8 +452,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
437452
// these structures in the UI-thread block. `NSMutableArray` is not thread
438453
// safe so we rely on the fact that we never mutate it after it's passed to
439454
// the main thread.
440-
[rootShadowView collectRootUpdatedFrames:viewsWithNewFrames
441-
parentConstraint:(CGSize){CSS_UNDEFINED, CSS_UNDEFINED}];
455+
[rootShadowView collectRootUpdatedFrames:viewsWithNewFrames];
442456

443457
// Parallel arrays are built and then handed off to main thread
444458
NSMutableArray *frameReactTags = [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];

React/Views/RCTShadowView.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#import "Layout.h"
1313
#import "RCTComponent.h"
14+
#import "RCTRootView.h"
1415

1516
@class RCTSparseArray;
1617

@@ -64,6 +65,12 @@ typedef void (^RCTApplierBlock)(RCTSparseArray *viewRegistry);
6465
- (void)setTopLeft:(CGPoint)topLeft;
6566
- (void)setSize:(CGSize)size;
6667

68+
/**
69+
* Size flexibility type used to find size constraints.
70+
* Default to RCTRootViewSizeFlexibilityNone
71+
*/
72+
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
73+
6774
/**
6875
* Border. Defaults to { 0, 0, 0, 0 }.
6976
*/
@@ -127,8 +134,7 @@ typedef void (^RCTApplierBlock)(RCTSparseArray *viewRegistry);
127134
* Calculate all views whose frame needs updating after layout has been calculated.
128135
* The viewsWithNewFrame set contains the reactTags of the views that need updating.
129136
*/
130-
- (void)collectRootUpdatedFrames:(NSMutableSet *)viewsWithNewFrame
131-
parentConstraint:(CGSize)parentConstraint;
137+
- (void)collectRootUpdatedFrames:(NSMutableSet *)viewsWithNewFrame;
132138

133139
/**
134140
* Recursively apply layout to children.

React/Views/RCTShadowView.m

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,32 @@ - (void)collectUpdatedProperties:(NSMutableSet *)applierBlocks
215215
}
216216
}
217217

218+
219+
- (void)applySizeConstraints
220+
{
221+
switch (_sizeFlexibility) {
222+
case RCTRootViewSizeFlexibilityNone:
223+
break;
224+
case RCTRootViewSizeFlexibilityWidth:
225+
_cssNode->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
226+
break;
227+
case RCTRootViewSizeFlexibilityHeight:
228+
_cssNode->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
229+
break;
230+
case RCTRootViewSizeFlexibilityWidthAndHeight:
231+
_cssNode->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
232+
_cssNode->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
233+
break;
234+
}
235+
}
236+
218237
- (void)collectRootUpdatedFrames:(NSMutableSet *)viewsWithNewFrame
219-
parentConstraint:(__unused CGSize)parentConstraint
220238
{
239+
RCTAssert(RCTIsReactRootView(self.reactTag),
240+
@"The method has been called on a view with react tag %@, which is not a root view", self.reactTag);
241+
242+
[self applySizeConstraints];
243+
221244
[self fillCSSNode:_cssNode];
222245
layoutNode(_cssNode, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
223246
[self applyLayoutNode:_cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:CGPointZero];
@@ -245,6 +268,7 @@ - (instancetype)init
245268
if ((self = [super init])) {
246269

247270
_frame = CGRectMake(0, 0, CSS_UNDEFINED, CSS_UNDEFINED);
271+
_sizeFlexibility = RCTRootViewSizeFlexibilityNone;
248272

249273
for (unsigned int ii = 0; ii < META_PROP_COUNT; ii++) {
250274
_paddingMetaProps[ii] = CSS_UNDEFINED;

0 commit comments

Comments
 (0)