Skip to content

Commit

Permalink
Add a -[FlutterViewController splashScreenView] property (flutter#6112
Browse files Browse the repository at this point in the history
)

Add a `-[FlutterViewController splashScreenView]` property

Add a `-[FlutterViewController splashScreenView]` property that
clients can use to customize the launch view (issue flutter#17140).
  • Loading branch information
jamesderlin authored Aug 30, 2018
1 parent a047fd2 commit 51d4be7
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ FLUTTER_EXPORT

- (id<FlutterPluginRegistry>)pluginRegistry;

/**
Specifies the view to use as a splash screen. Flutter's rendering is asynchronous, so the first
frame rendered by the Flutter application might not immediately appear when the Flutter view is
initially placed in the view hierarchy. The splash screen view will be used as a replacement
until the first frame is rendered.
The view used should be appropriate for multiple sizes; an autoresizing mask to have a flexible
width and height will be applied automatically.
If not specified, uses a view generated from `UILaunchStoryboardName` from the main bundle's
`Info.plist` file.
*/
@property(strong, nonatomic) UIView* splashScreenView;

@end

#endif // FLUTTER_FLUTTERVIEWCONTROLLER_H_
71 changes: 46 additions & 25 deletions shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ @implementation FlutterViewController {
// We keep a separate reference to this and create it ahead of time because we want to be able to
// setup a shell along with its platform view before the view has to appear.
fml::scoped_nsobject<FlutterView> _flutterView;
fml::scoped_nsobject<UIView> _launchView;
fml::scoped_nsobject<UIView> _splashScreenView;
UIInterfaceOrientationMask _orientationPreferences;
UIStatusBarStyle _statusBarStyle;
blink::ViewportMetrics _viewportMetrics;
Expand Down Expand Up @@ -322,47 +322,46 @@ - (void)loadView {
self.view.multipleTouchEnabled = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self installLaunchViewIfNecessary];
[self installSplashScreenViewIfNecessary];
}

#pragma mark - Managing launch views

- (void)installLaunchViewIfNecessary {
- (void)installSplashScreenViewIfNecessary {
// Show the launch screen view again on top of the FlutterView if available.
// This launch screen view will be removed once the first Flutter frame is rendered.
[_launchView.get() removeFromSuperview];
_launchView.reset();
NSString* launchStoryboardName =
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"UILaunchStoryboardName"];
if (launchStoryboardName && !self.isBeingPresented && !self.isMovingToParentViewController) {
UIViewController* launchViewController =
[[UIStoryboard storyboardWithName:launchStoryboardName bundle:nil]
instantiateInitialViewController];
_launchView.reset([launchViewController.view retain]);
_launchView.get().frame = self.view.bounds;
_launchView.get().autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:_launchView.get()];
if (self.isBeingPresented || self.isMovingToParentViewController) {
[_splashScreenView.get() removeFromSuperview];
_splashScreenView.reset();
return;
}

// Use the property getter to initialize the default value.
UIView* splashScreenView = self.splashScreenView;
if (splashScreenView == nil) {
return;
}
splashScreenView.frame = self.view.bounds;
[self.view addSubview:splashScreenView];
}

- (void)removeLaunchViewIfPresent {
if (!_launchView) {
- (void)removeSplashScreenViewIfPresent {
if (!_splashScreenView) {
return;
}

[UIView animateWithDuration:0.2
animations:^{
_launchView.get().alpha = 0;
_splashScreenView.get().alpha = 0;
}
completion:^(BOOL finished) {
[_launchView.get() removeFromSuperview];
_launchView.reset();
[_splashScreenView.get() removeFromSuperview];
_splashScreenView.reset();
}];
}

- (void)installLaunchViewCallback {
if (!_shell || !_launchView) {
- (void)installSplashScreenViewCallback {
if (!_shell || !_splashScreenView) {
return;
}
auto weak_platform_view = _shell->GetPlatformView();
Expand All @@ -381,18 +380,40 @@ - (void)installLaunchViewCallback {
// association. Thus, we are not convinced that the unsafe unretained weak object is in
// fact alive.
if (weak_platform_view) {
[weak_flutter_view_controller removeLaunchViewIfPresent];
[weak_flutter_view_controller removeSplashScreenViewIfPresent];
}
});
});
}

#pragma mark - Properties

- (UIView*)splashScreenView {
if (_splashScreenView == nullptr) {
NSString* launchStoryboardName =
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"UILaunchStoryboardName"];
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:launchStoryboardName bundle:nil];
if (storyboard == nil) {
return nil;
}
UIViewController* splashScreenViewController = [storyboard instantiateInitialViewController];
self.splashScreenView = splashScreenViewController.view;
}
return _splashScreenView.get();
}

- (void)setSplashScreenView:(UIView*)view {
_splashScreenView.reset([view retain]);
_splashScreenView.get().autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}

#pragma mark - Surface creation and teardown updates

- (void)surfaceUpdated:(BOOL)appeared {
// NotifyCreated/NotifyDestroyed are synchronous and require hops between the UI and GPU thread.
if (appeared) {
[self installLaunchViewCallback];
[self installSplashScreenViewCallback];
_shell->GetPlatformView()->NotifyCreated();

} else {
Expand Down

0 comments on commit 51d4be7

Please sign in to comment.