mirror of
https://github.com/status-im/react-native.git
synced 2025-02-25 15:45:32 +00:00
[WIP] Added loadingView property to RCTRootView
This commit is contained in:
parent
7e0064f097
commit
03889780b9
@ -11,6 +11,18 @@
|
||||
|
||||
#import "RCTBridge.h"
|
||||
|
||||
/**
|
||||
* This notification is sent when the first subviews are added to the root view
|
||||
* after the application has loaded. This is used to hide the `loadingView`, and
|
||||
* is a good indicator that the application is ready to use.
|
||||
*/
|
||||
extern NSString *const RCTContentDidAppearNotification;
|
||||
|
||||
/**
|
||||
* Native view used to host React-managed views within the app. Can be used just
|
||||
* like any ordinary UIView. You can have multiple RCTRootViews on screen at
|
||||
* once, all controlled by the same JavaScript application.
|
||||
*/
|
||||
@interface RCTRootView : UIView
|
||||
|
||||
/**
|
||||
@ -67,4 +79,18 @@
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) UIView *contentView;
|
||||
|
||||
/**
|
||||
* A view to display while the JavaScript is loading, so users aren't presented
|
||||
* with a blank screen. By default this is nil, but you can override it with
|
||||
* (for example) a UIActivityIndicatorView or a placeholder image.
|
||||
*/
|
||||
@property (nonatomic, strong) UIView *loadingView;
|
||||
|
||||
/**
|
||||
* Timings for hiding the loading view after the content has loaded. Both of
|
||||
* these values default to 0.25 seconds.
|
||||
*/
|
||||
@property (nonatomic, assign) NSTimeInterval loadingViewFadeDelay;
|
||||
@property (nonatomic, assign) NSTimeInterval loadingViewFadeDuration;
|
||||
|
||||
@end
|
||||
|
@ -25,6 +25,8 @@
|
||||
#import "RCTWebViewExecutor.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";
|
||||
|
||||
@interface RCTBridge (RCTRootView)
|
||||
|
||||
@property (nonatomic, weak, readonly) RCTBridge *batchedBridge;
|
||||
@ -39,6 +41,8 @@
|
||||
|
||||
@interface RCTRootContentView : RCTView <RCTInvalidating>
|
||||
|
||||
@property (nonatomic, readonly) BOOL contentHasAppeared;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame bridge:(RCTBridge *)bridge;
|
||||
|
||||
@end
|
||||
@ -64,14 +68,23 @@
|
||||
|
||||
_bridge = bridge;
|
||||
_moduleName = moduleName;
|
||||
_loadingViewFadeDelay = 0.25;
|
||||
_loadingViewFadeDuration = 0.25;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(javaScriptDidLoad:)
|
||||
name:RCTJavaScriptDidLoadNotification
|
||||
object:_bridge];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(hideLoadingView)
|
||||
name:RCTContentDidAppearNotification
|
||||
object:self];
|
||||
if (!_bridge.batchedBridge.isLoading) {
|
||||
[self bundleFinishedLoading:_bridge.batchedBridge];
|
||||
}
|
||||
|
||||
[self showLoadingView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -106,6 +119,41 @@
|
||||
RCT_IMPORT_METHOD(AppRegistry, runApplication)
|
||||
RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
|
||||
|
||||
- (void)setLoadingView:(UIView *)loadingView
|
||||
{
|
||||
_loadingView = loadingView;
|
||||
if (!_contentView.contentHasAppeared) {
|
||||
[self showLoadingView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showLoadingView
|
||||
{
|
||||
if (_loadingView && !_contentView.contentHasAppeared) {
|
||||
_loadingView.hidden = NO;
|
||||
[self addSubview:_loadingView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hideLoadingView
|
||||
{
|
||||
if (_loadingView.superview == self && _contentView.contentHasAppeared) {
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_loadingViewFadeDelay * NSEC_PER_SEC)),
|
||||
dispatch_get_main_queue(), ^{
|
||||
|
||||
[UIView transitionWithView:self
|
||||
duration:_loadingViewFadeDuration
|
||||
options:UIViewAnimationOptionTransitionCrossDissolve
|
||||
animations:^{
|
||||
_loadingView.hidden = YES;
|
||||
} completion:^(BOOL finished) {
|
||||
[_loadingView removeFromSuperview];
|
||||
}];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)javaScriptDidLoad:(NSNotification *)notification
|
||||
{
|
||||
RCTBridge *bridge = notification.userInfo[@"bridge"];
|
||||
@ -119,24 +167,18 @@ RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Every root view that is created must have a unique React tag.
|
||||
* Numbering of these tags goes from 1, 11, 21, 31, etc
|
||||
*
|
||||
* NOTE: Since the bridge persists, the RootViews might be reused, so now
|
||||
* the React tag is assigned every time we load new content.
|
||||
*/
|
||||
[_contentView removeFromSuperview];
|
||||
_contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds
|
||||
bridge:bridge];
|
||||
_contentView.backgroundColor = self.backgroundColor;
|
||||
[self addSubview:_contentView];
|
||||
[self insertSubview:_contentView atIndex:0];
|
||||
|
||||
NSString *moduleName = _moduleName ?: @"";
|
||||
NSDictionary *appParameters = @{
|
||||
@"rootTag": _contentView.reactTag,
|
||||
@"initialProps": _initialProperties ?: @{},
|
||||
};
|
||||
|
||||
[bridge enqueueJSCall:@"AppRegistry.runApplication"
|
||||
args:@[moduleName, appParameters]];
|
||||
});
|
||||
@ -145,9 +187,11 @@ RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
if (_contentView) {
|
||||
_contentView.frame = self.bounds;
|
||||
}
|
||||
_loadingView.center = (CGPoint){
|
||||
CGRectGetMidX(self.bounds),
|
||||
CGRectGetMidY(self.bounds)
|
||||
};
|
||||
}
|
||||
|
||||
- (NSNumber *)reactTag
|
||||
@ -155,6 +199,13 @@ RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
|
||||
return _contentView.reactTag;
|
||||
}
|
||||
|
||||
- (void)contentViewInvalidated
|
||||
{
|
||||
[_contentView removeFromSuperview];
|
||||
_contentView = nil;
|
||||
[self showLoadingView];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
@ -193,6 +244,18 @@ RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)insertReactSubview:(id<RCTViewNodeProtocol>)subview atIndex:(NSInteger)atIndex
|
||||
{
|
||||
[super insertReactSubview:subview atIndex:atIndex];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!_contentHasAppeared) {
|
||||
_contentHasAppeared = YES;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTContentDidAppearNotification
|
||||
object:self.superview];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
super.frame = frame;
|
||||
@ -237,7 +300,7 @@ RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
|
||||
{
|
||||
if (self.isValid) {
|
||||
self.userInteractionEnabled = NO;
|
||||
[self removeFromSuperview];
|
||||
[(RCTRootView *)self.superview contentViewInvalidated];
|
||||
[_bridge enqueueJSCall:@"ReactNative.unmountComponentAtNodeAndRemoveContainer"
|
||||
args:@[self.reactTag]];
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user