Skip to content

Commit 4d37cf0

Browse files
sherginfacebook-github-bot
authored andcommitted
RCTSurface: RCTSurfaceHostingView, interop layer beteween UIKit and RCTSurface
Summary: UIView subclass which providers interoperability between UIKit and Surface regarding layout and life-cycle. Reviewed By: rsnara Differential Revision: D6465922 fbshipit-source-id: 2a7cfb70119d460bc22968d1aa780833bf47d7f6
1 parent c8e72bb commit 4d37cf0

File tree

5 files changed

+380
-1
lines changed

5 files changed

+380
-1
lines changed

React/Base/Surface/RCTSurface.mm

+1
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ - (void)_registerRootView
323323
}
324324

325325
RCTUIManager *uiManager = batchedBridge.uiManager;
326+
326327
RCTExecuteOnUIManagerQueue(^{
327328
[uiManager registerRootViewTag:self->_rootViewTag];
328329

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
#import <UIKit/UIKit.h>
11+
12+
#import <React/RCTSurfaceSizeMeasureMode.h>
13+
#import <React/RCTSurfaceStage.h>
14+
15+
@class RCTBridge;
16+
@class RCTSurface;
17+
18+
typedef UIView *(^RCTSurfaceHostingViewActivityIndicatorViewFactory)();
19+
20+
NS_ASSUME_NONNULL_BEGIN
21+
22+
/**
23+
* UIView subclass which providers interoperability between UIKit and
24+
* Surface regarding layout and life-cycle.
25+
* This class can be used as easy-to-use general purpose integration point
26+
* of ReactNative-powered experiences in UIKit based apps.
27+
*/
28+
@interface RCTSurfaceHostingView : UIView
29+
30+
/**
31+
* Designated initializer.
32+
* Instanciates a view with given Surface object.
33+
* Note: The view retains the surface object.
34+
*/
35+
- (instancetype)initWithSurface:(RCTSurface *)surface NS_DESIGNATED_INITIALIZER;
36+
37+
/**
38+
* Convenience initializer.
39+
* Instanciates a Surface object with given `bridge`, `moduleName`, and
40+
* `initialProperties`, and then use it to instanciate a view.
41+
*/
42+
- (instancetype)initWithBridge:(RCTBridge *)bridge
43+
moduleName:(NSString *)moduleName
44+
initialProperties:(NSDictionary *)initialProperties;
45+
46+
/**
47+
* Surface object which is currently using to power the view.
48+
* Read-only.
49+
*/
50+
@property (nonatomic, strong, readonly) RCTSurface *surface;
51+
52+
/**
53+
* Size measure mode which are defining relationship between UIKit and ReactNative
54+
* layout approaches.
55+
* Defaults to `RCTSurfaceSizeMeasureModeWidthAtMost | RCTSurfaceSizeMeasureModeHeightAtMost`.
56+
*/
57+
@property (nonatomic, assign) RCTSurfaceSizeMeasureMode sizeMeasureMode;
58+
59+
/**
60+
* Activity indicator factory.
61+
* A hosting view may use this block to instantiate and display custom activity
62+
* (loading) indicator (aka "spinner") when it needed.
63+
* Defaults to `nil` (no activity indicator).
64+
*/
65+
@property (nonatomic, copy, nullable) RCTSurfaceHostingViewActivityIndicatorViewFactory activityIndicatorViewFactory;
66+
67+
@end
68+
69+
NS_ASSUME_NONNULL_END
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
#import "RCTSurfaceHostingView.h"
11+
12+
#import "RCTDefines.h"
13+
#import "RCTSurface.h"
14+
#import "RCTSurfaceDelegate.h"
15+
#import "RCTSurfaceView.h"
16+
#import "RCTUtils.h"
17+
18+
@interface RCTSurfaceHostingView () <RCTSurfaceDelegate>
19+
20+
@property (nonatomic, assign) BOOL isActivityIndicatorViewVisible;
21+
@property (nonatomic, assign) BOOL isSurfaceViewVisible;
22+
23+
@end
24+
25+
@implementation RCTSurfaceHostingView {
26+
UIView *_Nullable _activityIndicatorView;
27+
UIView *_Nullable _surfaceView;
28+
RCTSurfaceStage _stage;
29+
}
30+
31+
RCT_NOT_IMPLEMENTED(- (instancetype)init)
32+
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
33+
RCT_NOT_IMPLEMENTED(- (nullable instancetype)initWithCoder:(NSCoder *)coder)
34+
35+
- (instancetype)initWithBridge:(RCTBridge *)bridge
36+
moduleName:(NSString *)moduleName
37+
initialProperties:(NSDictionary *)initialProperties
38+
{
39+
RCTSurface *surface =
40+
[[RCTSurface alloc] initWithBridge:bridge
41+
moduleName:moduleName
42+
initialProperties:initialProperties];
43+
44+
return [self initWithSurface:surface];
45+
}
46+
47+
- (instancetype)initWithSurface:(RCTSurface *)surface
48+
{
49+
if (self = [super initWithFrame:CGRectZero]) {
50+
_surface = surface;
51+
52+
_sizeMeasureMode =
53+
RCTSurfaceSizeMeasureModeWidthAtMost |
54+
RCTSurfaceSizeMeasureModeHeightAtMost;
55+
56+
_surface.delegate = self;
57+
_stage = surface.stage;
58+
[self _updateViews];
59+
}
60+
61+
return self;
62+
}
63+
64+
- (CGSize)intrinsicContentSize
65+
{
66+
if (RCTSurfaceStageIsPreparing(_stage)) {
67+
if (_activityIndicatorView) {
68+
return _activityIndicatorView.intrinsicContentSize;
69+
}
70+
71+
return CGSizeZero;
72+
}
73+
74+
return _surface.intrinsicSize;
75+
}
76+
77+
- (CGSize)sizeThatFits:(CGSize)size
78+
{
79+
if (RCTSurfaceStageIsPreparing(_stage)) {
80+
if (_activityIndicatorView) {
81+
return [_activityIndicatorView sizeThatFits:size];
82+
}
83+
84+
return CGSizeZero;
85+
}
86+
87+
CGSize minumumSize = CGSizeZero;
88+
CGSize maximumSize = CGSizeMake(INFINITY, INFINITY);
89+
90+
if (_sizeMeasureMode & RCTSurfaceSizeMeasureModeWidthExact) {
91+
minumumSize.width = size.width;
92+
maximumSize.width = size.width;
93+
}
94+
else if (_sizeMeasureMode & RCTSurfaceSizeMeasureModeWidthAtMost) {
95+
maximumSize.width = size.width;
96+
}
97+
98+
if (_sizeMeasureMode & RCTSurfaceSizeMeasureModeHeightExact) {
99+
minumumSize.height = size.height;
100+
maximumSize.height = size.height;
101+
}
102+
else if (_sizeMeasureMode & RCTSurfaceSizeMeasureModeHeightAtMost) {
103+
maximumSize.height = size.height;
104+
}
105+
106+
return [_surface sizeThatFitsMinimumSize:minumumSize
107+
maximumSize:maximumSize];
108+
}
109+
110+
- (void)setStage:(RCTSurfaceStage)stage
111+
{
112+
if (stage == _stage) {
113+
return;
114+
}
115+
116+
BOOL shouldInvalidateLayout =
117+
RCTSurfaceStageIsRunning(stage) != RCTSurfaceStageIsRunning(_stage) ||
118+
RCTSurfaceStageIsPreparing(stage) != RCTSurfaceStageIsPreparing(_stage);
119+
120+
_stage = stage;
121+
122+
if (shouldInvalidateLayout) {
123+
[self _invalidateLayout];
124+
[self _updateViews];
125+
}
126+
}
127+
128+
- (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
129+
{
130+
if (sizeMeasureMode == _sizeMeasureMode) {
131+
return;
132+
}
133+
134+
_sizeMeasureMode = sizeMeasureMode;
135+
[self _invalidateLayout];
136+
}
137+
138+
#pragma mark - isActivityIndicatorViewVisible
139+
140+
- (void)setIsActivityIndicatorViewVisible:(BOOL)visible
141+
{
142+
if (_isActivityIndicatorViewVisible == visible) {
143+
return;
144+
}
145+
146+
if (visible) {
147+
if (_activityIndicatorViewFactory) {
148+
_activityIndicatorView = _activityIndicatorViewFactory();
149+
_activityIndicatorView.frame = self.bounds;
150+
_activityIndicatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
151+
[self addSubview:_activityIndicatorView];
152+
}
153+
} else {
154+
[_activityIndicatorView removeFromSuperview];
155+
_activityIndicatorView = nil;
156+
}
157+
}
158+
159+
#pragma mark - isSurfaceViewVisible
160+
161+
- (void)setIsSurfaceViewVisible:(BOOL)visible
162+
{
163+
if (_isSurfaceViewVisible == visible) {
164+
return;
165+
}
166+
167+
if (visible) {
168+
_surfaceView = _surface.view;
169+
_surfaceView.frame = self.bounds;
170+
_surfaceView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
171+
[self addSubview:_surfaceView];
172+
} else {
173+
[_surfaceView removeFromSuperview];
174+
_surfaceView = nil;
175+
}
176+
}
177+
178+
#pragma mark - activityIndicatorViewFactory
179+
180+
- (void)setActivityIndicatorViewFactory:(RCTSurfaceHostingViewActivityIndicatorViewFactory)activityIndicatorViewFactory
181+
{
182+
_activityIndicatorViewFactory = activityIndicatorViewFactory;
183+
if (_isActivityIndicatorViewVisible) {
184+
_isActivityIndicatorViewVisible = NO;
185+
self.isActivityIndicatorViewVisible = YES;
186+
}
187+
}
188+
189+
#pragma mark - Private stuff
190+
191+
- (void)_invalidateLayout
192+
{
193+
[self.superview setNeedsLayout];
194+
}
195+
196+
- (void)_updateViews
197+
{
198+
self.isSurfaceViewVisible = RCTSurfaceStageIsRunning(_stage);
199+
self.isActivityIndicatorViewVisible = RCTSurfaceStageIsPreparing(_stage);
200+
}
201+
202+
- (void)didMoveToWindow
203+
{
204+
[super didMoveToWindow];
205+
[self _updateViews];
206+
}
207+
208+
#pragma mark - RCTSurfaceDelegate
209+
210+
- (void)surface:(RCTSurface *)surface didChangeStage:(RCTSurfaceStage)stage
211+
{
212+
RCTExecuteOnMainQueue(^{
213+
[self setStage:stage];
214+
});
215+
}
216+
217+
- (void)surface:(RCTSurface *)surface didChangeIntrinsicSize:(CGSize)intrinsicSize
218+
{
219+
RCTExecuteOnMainQueue(^{
220+
[self _invalidateLayout];
221+
});
222+
}
223+
224+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
#import <UIKit/UIKit.h>
11+
12+
/**
13+
* Bitmask defines how size constrains from `-[UIView sizeThatFits:]`
14+
* are translated to `-[RCTSurface sizeThatFitsMinimumSize:maximumSize:]`.
15+
*/
16+
typedef NS_OPTIONS(NSInteger, RCTSurfaceSizeMeasureMode) {
17+
RCTSurfaceSizeMeasureModeWidthUndefined = 0 << 0,
18+
RCTSurfaceSizeMeasureModeWidthExact = 1 << 0,
19+
RCTSurfaceSizeMeasureModeWidthAtMost = 2 << 0,
20+
RCTSurfaceSizeMeasureModeHeightUndefined = 0 << 2,
21+
RCTSurfaceSizeMeasureModeHeightExact = 1 << 2,
22+
RCTSurfaceSizeMeasureModeHeightAtMost = 2 << 2,
23+
};

0 commit comments

Comments
 (0)