From 51d4be7745d58c68eccf7ce89dea2934a2ea7ed0 Mon Sep 17 00:00:00 2001 From: "James D. Lin" Date: Thu, 30 Aug 2018 15:13:28 -0700 Subject: [PATCH] Add a `-[FlutterViewController splashScreenView]` property (#6112) Add a `-[FlutterViewController splashScreenView]` property Add a `-[FlutterViewController splashScreenView]` property that clients can use to customize the launch view (issue #17140). --- .../framework/Headers/FlutterViewController.h | 14 ++++ .../framework/Source/FlutterViewController.mm | 71 ++++++++++++------- 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h b/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h index 6250089aed536..e640bb7a8a65b 100644 --- a/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h @@ -53,6 +53,20 @@ FLUTTER_EXPORT - (id)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_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 27b8e3738ce76..2fb9f90c6f281 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -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; - fml::scoped_nsobject _launchView; + fml::scoped_nsobject _splashScreenView; UIInterfaceOrientationMask _orientationPreferences; UIStatusBarStyle _statusBarStyle; blink::ViewportMetrics _viewportMetrics; @@ -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(); @@ -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 {