Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a -[FlutterViewController launchView] property #6112

Merged
merged 2 commits into from
Aug 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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