React-native: [初始化] 启动画面白闪

创建于 2015-05-26  ·  138评论  ·  资料来源: facebook/react-native

我只是想知道是否有关于 LaunchScreen 的好做法。 我问这个的原因是,如果添加 LaunchScreen,在 react-native 启动并加载应用程序之前会有一个白色的闪光。 有什么办法可以防止这种情况发生吗?

AsyncStorage Locked

最有用的评论

要添加到此...

我发现的一个解决方案是为rootView分配背景颜色,但使用[UIColor colorWithPatternImage:img]

这不需要任何延迟来确保它在完全加载之前保持可见。

下面是一个完整的片段(并使用@dvine-multimedia 提供的提示),它将为设备找到所需的 LaunchImage:

NSArray *allPngImageNames = [[NSBundle mainBundle] pathsForResourcesOfType:@"png" inDirectory:nil];
  for (NSString *imgName in allPngImageNames){
    if ([imgName containsString:@"LaunchImage"]){
      UIImage *img = [UIImage imageNamed:imgName];

      if (img.scale == [UIScreen mainScreen].scale && CGSizeEqualToSize(img.size, [UIScreen mainScreen].bounds.size)) {
        rootView.backgroundColor = [UIColor colorWithPatternImage:img];
      }
  }
}

LaunchImage 现在保持可见,直到 react-native 包完全加载。

所有138条评论

@alinz - 这在下一个版本中得到修复: https :

@liubko是的,这正是我想要摆脱的。 我还没有应用补丁,但我今晚会去做。

@brentvatne :我不知道该补丁将如何解决这个问题(如果我是盲人/愚蠢的人,请原谅:-)。 问题是在应用程序启动和 React 仍在工作之间有一段时间。 理想情况下,LaunchScreen 将显示直到 React 完成并完全呈现,就像它在“完全原生”应用程序中所做的那样。

@oblador - 啊,这将使您在“闪烁”时刻具有与启动屏幕相同的背景颜色,从而使您能够更顺畅地过渡。

@vjeux - 你如何在 FB 应用程序中解决这个问题? 我注意到 F8,如果我理解正确的话,它是 100% React Native,它直接从启动屏幕转换到应用程序。 抄送@nicklockwood

这个问题也有一个(单独的)修复程序。 使用RCTRootView的新loadingView属性,并将其设置为全屏显示您的启动图像的UIImageView 。 代码可能如下所示:

UIImageView *launchView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MyLaunchImage"];
rootView.loadingView = launchView;

我一直在尝试一种自动检测启动图像并使之完全自动化的方法,但它还没有真正准备好。 如果你有兴趣,它看起来像这样:

// TODO: support landscape orientation

// Get launch image
NSString *launchImageName = nil;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
  CGFloat height = MAX(RCTScreenSize().width, RCTScreenSize().height);
  if (height == 480) launchImageName = @"[email protected]"; // iPhone 4/4s
  else if (height == 568) launchImageName = @"[email protected]"; // iPhone 5/5s
  else if (height == 667) launchImageName = @"[email protected]"; // iPhone 6
  else if (height == 736) launchImageName = @"[email protected]"; // iPhone 6+
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
  CGFloat scale = RCTScreenScale();
  if (scale == 1) launchImageName = @"LaunchImage-700-Portrait~ipad.png"; // iPad
  else if (scale == 2) launchImageName = @"LaunchImage-700-Portrait@2x~ipad.png"; // Retina iPad
}

// Create loading view
UIImage *image = [UIImage imageNamed:launchImageName];
if (image) {
  UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRect){CGPointZero, RCTScreenSize()}];
  imageView.contentMode = UIViewContentModeBottom;
  imageView.image = image;
  rootView.loadingView = imageView;
}

如果您使用的是 iOS 8+,@ nicklockwood所描述的一个简单的解决方案是加载启动屏幕 xib。

@ide我正在使用启动屏幕 xib。 我在启动时看到了我的 lauchscreen 视图,但在我的应用程序启动之前,我看到了一个白色视图(闪烁)。

@alinz ,我相信@ide意味着使用您的启动屏幕 xib 来设置 RCTRootView loadingView(您仍然需要手动执行)。 没有自动支持这样做(还)。

澄清一下,iOS 会在 React _begins_ 加载时隐藏您的启动屏幕。 为避免看到空白屏幕,您需要通过手动显示与 RCTRootView 的加载视图相同的视图来延长显示启动屏幕的时间。

感谢@nicklockwood的澄清。 那是我的坏处。 :)

http://stackoverflow.com/a/29115477/255765 的Curtesy 我最终得到了这个:

for (NSString *imgName in allPngImageNames){
    // Find launch images
    if ([imgName containsString:@"LaunchImage"]){
      UIImage *img = [UIImage imageNamed:imgName]; //-- this is a launch image
      // Has image same scale and dimensions as our current device's screen?
      if (img.scale == [UIScreen mainScreen].scale && CGSizeEqualToSize(img.size, [UIScreen mainScreen].bounds.size)) {
        NSLog(@"Found launch image for current device %@", img.description);
        UIImageView *launchView = [[UIImageView alloc] initWithImage: img];
        rootView.loadingView = launchView;
      }
    }
  }

似乎工作。

+1 用于标准/记录方式。

@dvine-multimedia 是否比我上面提供的代码片段效果更好?

@ myusuf3

@nicklockwood实际上,他们做的事情非常相似。 当我开始研究这个时,我可能不明白如何处理你的剪辑,因为完全缺乏任何 xcode 经验。 当我终于明白该怎么做时,我没有意识到,你已经在那里了。 除此之外,我个人认为“我的”解决方案更具可读性。 但那纯粹的美学。

@nicklockwood我试过你的代码,但我仍然看到一个白色的闪光。 我创建了一个启动图像以设置为加载视图。 启动图像与launchScreen.xib 相同。

这是唯一能保持我们应用程序发布的东西。 真的很感谢这方面的任何帮助。

是隐藏启动画面后闪现,还是启动画面不显示? (这可能很难通过查看来确定 - 暂时将启动图像更改为纯红色矩形之类的东西以确保)。

@nicklockwood我试图更改 xib 文件和 launchScreen Image 之间的颜色。 我仍然看到那个闪光。

我的代码如下所示:

 UIImageView *launchView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"launchScreen1"]];
 rootView.loadingView = launchView;

 rootView.loadingViewFadeDelay = 0.0;
 rootView.loadingViewFadeDuration = 0.15;

我现在删除了最后两行 loadingViewFadeDelay 和持续时间,似乎问题解决了。 我没有看到任何闪光。 不错的平滑过渡。

@chirag04我只是用示例项目试过了,我没有看到闪光灯:(

这是我所做的

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"whiteFlash"
                                                   launchOptions:launchOptions];

  //here's what I did
  UIImage *image = [UIImage imageNamed:@"LaunchImage"];
  if (image) {
    UIImageView *launchView = [[UIImageView alloc] initWithImage: image];
    launchView.contentMode = UIViewContentModeBottom;
    launchView.image = image;
    rootView.loadingView = launchView;
  }
  ///////////////////////////

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [[UIViewController alloc] init];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;

行。 深入挖掘,似乎闪存可能是因为我的应用程序在从 asyncstore 加载值之前不会呈现任何内容。

render() {
  if(!this.state.loaded) return (null);
  return <View ...../>;
}

我认为loadingView认为js完成了渲染并隐藏了loadingView。 然而 js 刚刚完成渲染return null

@nicklockwood @alinz我只是在空中射击。 可能不是真正的原因。 你们有什么感想。

另外我注意到的一件事是,如果我将那些 loadingViewFadeDelay 等值设置为 0.30 或更高,则过渡非常平滑。 默认值为 0.25,这也是平滑的。

loadingFadeDelay 的目的正是为了涵盖您的应用程序不会立即呈现任何内容的场景,因此您可以正确使用它。

不过,您可能需要考虑明确设置 loadingViewFadeDelay,以防默认值发生变化 - 并确保在您支持的最慢设备上进行测试,以防加载时间更长。

我喜欢@nicklockwood解决方案,但您必须考虑无法预测的网络延迟。

另一种解决方案是,将组件状态设置为某种默认值,以告诉您的组件显示某种加载对话框。

凉爽的。 我想我有解决办法。

你们如何看待 3 个组件都相同。

1) launchScreen.xib
2) loadingView
3) return null in render to actually render a view which is like loadingView and launchScreen.xib?

不确定第 3 点将如何在不同设备上扩展。 你们甚至会建议吗?

如果启动时间取决于网络然后测试,我绝对提倡立即绘制一个“空”视图,而不是希望它的下载速度比淡入淡出延迟更快。

取决于异步存储。 没有网络

无论您是否依赖网络,我都不太喜欢使用时基显示。 您无法100%保证您设置的时间准确无误。 您应该始终向用户显示某些内容以表明某些内容正在发生但尚未准备好显示。 这只是一个建议。

同意。 loadingView 的目的,就像标准的 iOS 加载图像一样,只是覆盖直到你的应用程序准备好显示一些东西,即使所有的应用程序都准备好显示是一个加载微调器。

也就是说,我将其设为视图而不是图像的原因是您可以将其设为非静态。 如果需要,您可以将 UIActivityIndi​​catorView 添加到 loadingView。

如何定位发射图像? 我试过调整框架原点,但无论我使用什么原点,它总是将其定位在中心。 我有一个小的顶部栏图像,我想将其放置在顶部并从左向右拉伸。

这就是我所拥有的:

  UIImageView *launchView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"LaunchImage"]];
  CGRect frame = launchView.frame;
  frame.origin.x = 0;
  frame.origin.y = 0;
  launchView.frame = frame;
  rootView.loadingView = launchView;
  rootView.loadingViewFadeDelay = 0.0;
  rootView.loadingViewFadeDuration = 0.0;

它不是启动图像,而是启动_view_,因此您可以将 imageView 放置在另一个容器视图中,并将该容器用作启动视图:

UIView *launchView = [[UIView alloc] init];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"LaunchImage"]];
imageView.frame = CGRectMake(whatever);
[launchView addSubview:imageView];
...

是的,我想我可以让包装器填充屏幕空间并将图像放置在顶部。 包装器将被 RootView 自动定位在中心,它似乎https://github.com/facebook/react-native/blob/757d6d204ae2d743634af64e3f78a4aad9d53f70/React/Base/RCTRootView.m#L191。

@Intellicode是的。

刚刚使用@dvine-multimedia 的代码在 iphone 4s 上破坏了我的应用程序。 解决方法是在 if 中休息一下。

又一次崩溃,因为containsString在 ios 7 上不可用。

@nicklockwood想知道加载视图是否会自动选择最佳分辨率?

loadingView 根本不选择图像,它只使用您传入的内容。我在上面发布的用于查找启动时间的代码段将为设备选择正确的分辨率。

不过,您的代码段并未选择尺寸正确的代码段。 有什么解决办法吗?

您使用的是我的解决方案还是 dvine 的解决方案? 您使用的是什么 iPhone 型号? 纵向还是横向?

使用 dvine 时,它​​会选择正确的维度。 使用您的解决方案,图像周围有黑色空间。 我假设黑色空间是因为它拾取了尺寸错误的图像。

我在 iphone 6. 肖像。

这是它的样子。 注意白色背景。

使用以下代码:

UIImageView *launchView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"LaunchImage"]];
  rootView.loadingView = launchView;
  rootView.loadingViewFadeDelay = 0.20;
  rootView.loadingViewFadeDuration = 0.20;

lrn_launch_screen

那不是我发布的解决方案,这是:

// Get launch image
NSString *launchImageName = nil;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
  CGFloat height = MAX(RCTScreenSize().width, RCTScreenSize().height);
  if (height == 480) launchImageName = @"[email protected]"; // iPhone 4/4s
  else if (height == 568) launchImageName = @"[email protected]"; // iPhone 5/5s
  else if (height == 667) launchImageName = @"[email protected]"; // iPhone 6
  else if (height == 736) launchImageName = @"[email protected]"; // iPhone 6+
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
  CGFloat scale = RCTScreenScale();
  if (scale == 1) launchImageName = @"LaunchImage-700-Portrait~ipad.png"; // iPad
  else if (scale == 2) launchImageName = @"LaunchImage-700-Portrait@2x~ipad.png"; // Retina iPad
}

// Create loading view
UIImage *image = [UIImage imageNamed:launchImageName];
if (image) {
  UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRect){CGPointZero, RCTScreenSize()}];
  imageView.contentMode = UIViewContentModeBottom;
  imageView.image = image;
  rootView.loadingView = imageView;
}

哦,该死的! 我希望我仔细阅读你的评论。 您的解决方案有效,而且也很容易理解。

I've been experimenting with a way to automatically detect the launch image and make this completely automatic, but it's not really ready yet. If you're interested, it looks like this:

也许它的experimenting事情。 不知道我是怎么错过的。 对不起这是我的错。

感谢这里的帮助。 将在下一个版本中定义使用此代码。 似乎也涵盖了所有情况。 不需要风景。

嘿,我想我低估了它。 我可能应该说“这就是我们现在在生产中使用的东西,它似乎工作正常”:-)

“这就是我们现在在生产中使用的”将使我们免于在应用商店中获得一些 1 星。 哈哈。 不用担心。 总有一个新版本来拯救世界。 :)

顺便关闭这个问题?

我会去关闭这张票,因为它已经详细讨论过,我们确实有一些很好的解决方案。

只是为了让那些使用 LaunchScreen xib 的人 100% 清楚这一点,这里是使之工作的代码:

UIView* launchScreenView = [[[NSBundle mainBundle] loadNibNamed:@"LaunchScreen" owner:self options:nil] objectAtIndex:0];
launchScreenView.frame = self.window.bounds;
rootView.loadingView = launchScreenView;

将这些行添加到AppDelegate.m文件中的application didFinishLaunchingWithOptions方法中,就在return YES行的上方。

@arnemart更清楚该方法仅适用于 ios 8+ 对吗?

@arnemart谢谢! 完美运行

对于那些使用LaunchImage ,您需要同时设置framecontentMode以使图像正确缩放:

UIImageView *launchScreenView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"LaunchImage"]];
launchScreenView.frame = self.window.bounds;
launchScreenView.contentMode = UIViewContentModeScaleAspectFill;
rootView.loadingView = launchScreenView;

就像从@arnemart的评论,添加这些行到application didFinishLaunchingWithOptions的方法AppDelegate.m文件,这行上述return YES

奇怪的。在 RN v.0.11.4 上,应用程序首先以黑屏启动,然后在加载应用程序之前启动 LaunchScreen.xib。 iOS 9 w/ @arnemart的修复https://github.com/facebook/react-native/issues/1402#issuecomment -130236507。有任何想法吗?

@irfaan尝试将

self.window.backgroundColor = [UIColor redColor];didFinishLaunchingWithOptions什么也没有改变。 在 LaunchScreen.xib 之前仍然是黑色的。 所以不是从窗户,似乎@nicklockwood

你如何建议我去调试这个?

听起来 iOS 在应用程序加载之前根本没有加载您的 launchScreen.xib(此时,React 将其显示为 loadingView)。

也许这是Xcode中的配置错误? 或者可能是 iOS 9 中的错误?

你在设备上试过,还是只在模拟器上试过?

谢谢@nicklockwood - 我在设备上遇到了这个问题。 在模拟器中运行它,它运行良好,然后删除并在设备上运行,它运行良好。 真的很奇怪。 如果问题再次出现,将再次发布。

@genexliu ,我将我的“LaunchImage”图像集添加到Images.xcassets/LaunchImage.launchimage/但是您粘贴的代码和我的 LaunchScreen.storyboard 都无法找到/使​​用它们(两者都以静默方式失败)。 当我看到它的背景颜色时,我的 LaunchScreen 故事板正在正确加载,但它没有显示引用的图像。 有任何想法吗?

此外,从 XCode 运行时的启动顺序看起来很正常,但是从 cmd 行运行natal launch时,似乎有额外的启动顺序/额外的白色闪光/等运行。

原来我的 Storyboard 没有找到 LaunchImage 的问题显然是 XCode 的一个错误。 我将启动设置更改为“使用资产目录”,然后再更改为“使用故事板”,然后它就开始工作了。 目前尚不清楚@genexliu的代码是否对我loadingViewFadeDelay似乎没有任何效果。

这是我的代码:

  UIImageView *launchScreenView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Images/LaunchImage"]];
  launchScreenView.frame = self.window.bounds;
  launchScreenView.contentMode = UIViewContentModeScaleAspectFill;
  rootView.loadingView = launchScreenView;
  rootView.loadingViewFadeDelay = 5000;

但是在故事板 LaunchImage 显示和我最初的 React render之间没有延迟。

@"Images/LaunchImage" 对我来说不合适。 可能只是@"LaunchImage"

哦,哦,是的。 你说得对。 那是一个错误的粘贴——我尝试过的排列之一(但不是第一个)。

另外,请查看我 3 个月前评论中的示例代码 - 有很多针对不同设备类别的启动图像文件。

呸! 你是对的。 切换回LaunchImage它现在可以工作了。 谢谢!

任何人都可以向我指出有关此 Android 的任何文档吗?

+1 安卓版

cc @dmmiller我们在 Android 上有加载视图功能吗?

嗨,我遇到了同样的问题,虽然我看到这里有一些已发布的解决方案,但我不明白把这段代码放在哪里。 根据我的理解,解决方案是更改 Objective-C 代码,而不是 React Native 本身可以完成的事情,对吗? 在这种情况下,发布的代码去哪里了? 在 xcode 项目根目录的 main.m 文件中? 谢谢。

@CorpusCallosum代码应该放在 AppDelegate.m 文件中,其中设置了 RCTRootView。

谢谢@nicklockwood ,我会尝试一下。

嘿,这段代码现在对我有用,就我没有看到白色闪光而言,我的图像正在加载到那个初始屏幕,但是,现在我的实际应用程序无法加载! 它只是停留在那个加载屏幕上,虽然我可以在我的控制台中看到应用程序已加载并正在运行,甚至交互也在工作(点击和滑动),但我实际上根本看不到我的应用程序,它只是卡住了在那个初始屏幕上。 知道为什么吗?

这是我的 AppDelegate.m 文件中的代码:

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [[UIViewController alloc] init];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];

  //use launch image as BG image for app
  UIImageView *launchScreenView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"LaunchImage-blank-grey"]];
  launchScreenView.frame = self.window.bounds;
  launchScreenView.contentMode = UIViewContentModeScaleAspectFill;
  rootView.loadingView = launchScreenView;
  rootView.loadingViewFadeDelay = 1000;

  return YES;

@CorpusCallosum您可以尝试删除该行
rootView.loadingViewFadeDelay = 1000;
或者用它的值微调启动画面和你的应用程序之间的过渡(我认为单位是秒,而不是毫秒,这就是为什么它看起来“卡在”启动画面上)。
如果完全删除该行对您不起作用,请尝试将值设置在 0-5 之间(您也可以设置非整数值)。

为我工作,谢谢大家:)

对于那些想要使用他们的启动屏幕 xib 作为加载视图的人,这里是插入到 AppDelegate.m 的代码:

UIView *loading = [[[NSBundle mainBundle] loadNibNamed:@"LaunchScreen" owner:self options:nil] objectAtIndex:0];
rootView.loadingView = loading;
rootView.loadingViewFadeDelay = 1;

最后一行是可选的,正如我上面提到的,它设置了加载视图在移动到应用程序本身之前将停留的时间。

@david-a 非常感谢你! 自从我开始测试 react native 以来,我一直在处理这个问题。 👏

@david-a,@ geriux :我还必须设置launchScreenView.frame = CGRectZero;因为我的 LaunchScreen.xib 有一个带有 AspectFill 内容模式的背景图像,并且它没有正确缩放。 经过几次试验和错误后,我找到了解决方案,不确定是什么原因造成的。

@BasitAli是的,抱歉,应该更好地记录下来。 如果您将视图的大小设置为非零,它将在屏幕中居中。 如果您将其设置为零,它将被缩放以适合屏幕。

@david-a 非常感谢! 您的评论应该包含在样板文件中,或者至少是主要的 React Native 文档的一部分。 不知道为什么这个问题在 2015 年 3 月被关闭,它在 2016 年 2 月的 RN 0.20 中显然仍然存在。

如果有人可以为文档做 PR,那就太好了。

你们的建议对我有很大帮助(在 IOS 上,完美运行),有没有人找到在 Android 上解决这个问题的方法?

@weiyisheng ,我在 Android 上使用@braco建议的 react-native-splashscreen 以及上面在 iOS 上讨论的修复程序。

@braco @BasitAli是的,它有帮助,我将在我的应用程序中使用它,这是个好主意。 谢谢你们。

@BasitAli出于好奇为什么不在 iOS 上使用它?

我的应用程序从初始屏幕到登录屏幕无缝动画(徽标向上移动,登录字段跳出)。 rn-splashscreen 插件逐渐消失,这与我的动画效果不佳。 我不得不在 Android 上使用它,因为我别无选择。

@BasitAli看起来 react-native-splashscreen 插件遵循rootView.loadingViewFadeDuration设置,前提是您在附加后设置它,因此这应该禁用淡入淡出:

[RCTSplashScreen show:rootView];
rootView.loadingViewFadeDuration = 0;

有没有办法删除顶部的“从预捆绑文件加载”的小消息?

@rclai设置方案发布

啊! 谢谢!

是否有针对两个平台启动画面的本机解决方案? 输入两个平台的内部文件会使使用 react-native 无用。请简单回答。 谢谢

@rclai

有没有办法删除顶部的“从预捆绑文件加载”的小消息?

这在发布模式下不显示,只在调试模式下显示。 如果您也想在调试模式下隐藏它,您可以将[RCTDevLoadingView setEnabled:NO];隐藏在您的 AppDelegate 中。

@nicklockwood你好,对吗? 如果不是,我应该更改/删除什么?

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"SomeApp"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];

// Get launch image
NSString *launchImageName = nil;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
  CGFloat height = MAX(RCTScreenSize().width, RCTScreenSize().height);
  if (height == 480) launchImageName = @"[email protected]"; // iPhone 4/4s
  else if (height == 568) launchImageName = @"[email protected]"; // iPhone 5/5s
  else if (height == 667) launchImageName = @"[email protected]"; // iPhone 6
  else if (height == 736) launchImageName = @"[email protected]"; // iPhone 6+
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
  CGFloat scale = RCTScreenScale();
  if (scale == 1) launchImageName = @"LaunchImage-700-Portrait~ipad.png"; // iPad
  else if (scale == 2) launchImageName = @"LaunchImage-700-Portrait@2x~ipad.png"; // Retina iPad
}

// Create loading view
UIImage *image = [UIImage imageNamed:launchImageName];
if (image) {
  UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRect){CGPointZero, RCTScreenSize()}];
  imageView.contentMode = UIViewContentModeBottom;
  imageView.image = image;
  rootView.loadingView = imageView;
}

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;
}

@TeodorKolev在我看来是正确的。 如果您在启动时仍然看到闪烁,请尝试设置

rootView.loadingViewFadeDelay

更大的值(以秒为单位 - 默认为 0.25)

编辑:

这条线

UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRect){CGPointZero, RCTScreenSize()}];

应该只是

UIImageView *imageView = [[UIImageView alloc] init];

谢谢,我应该在哪个文件夹中添加这些图像? 为此我是否需要额外的 Contents.json? 我在该代码中遇到了多个错误
(https://cloud.githubusercontent.com/assets/10398337/13778676/e01e3d32-eabf-11e5-95bf-d7a1205a5ca1.png)
盯着:

CGFloat height = MAX(RCTScreenSize().width, RCTScreenSize().height);

@TeodorKolev Xcode 有一个用于添加它们的 GUI。 单击 Images.xcassets,然后单击 + 按钮并选择“App Icons & Launch Images”>“New iOS Launch Image”。

screen shot 2016-03-15 at 13 47 48

@TeodorKolev修复错误,您需要添加

#import "RCTUtils.h"

在您的 AppDelegate 中。

非常感谢,但我想看到启动画面,直到我的 WebView url 完全加载,现在它不是那样工作的。 尊重!

@nicklockwood你有什么补救办法吗?

目前解决这个问题的方法是什么? 由于问题出现已经一年零几个月了,我怀疑它是否真的会得到修复,所以我想知道目前的补救措施是什么。 哪些文件需要修改,哪些代码需要修改?

编辑:我只是使用带有 launchscreen.xib 的黑屏,但在应用程序完全加载之前它会在中途变成白色。

@hasen6问题已经解决,但开发人员需要做一些工作。

正如上面的评论中所讨论的,您需要设置带有一些内容的rootView.loadingView来代替白屏显示,并调整rootView.loadingViewFadeDelay以确保加载视图不会在您之前隐藏应用程序已完成加载。

如果你只是想显示一个黑屏,你可能不需要费心加载视图,只需将rootView.backgroundColor为黑色,但你必须进行试验。

我将rootView.backgroundColor = [UIColor clearColor];改为rootView.backgroundColor = [UIColor blackColor]; but it didn't make any difference. Doing a search in XCode for rootView.loadingView` 没有返回任何结果。

@hasen6您需要弄清楚白色的来源 - 可能是您的 JS 应用程序中有一个白色的视图,并且在内容加载之前显示了一段时间。

loadingViewRCTRootView一个属性,您大概在 AppDelegate 中有一个实例。 除非您自己添加,否则实际代码rootView.loadingView不会出现在您的 Xcode 中。 以下是您可能如何使用它的示例:

rootView.loadingView = [UIView new];
rootView.loadingView.backgroundColor = [UIColor blackColor];
rootView.loadingViewFadeDelay = 0.5; // measured in seconds

我的应用程序在任何地方都不是白色的。 显示启动屏幕后,我的所有应用程序在加载时都显示相同的白屏,因此我确定我的应用程序没有问题。

所以我需要将该代码添加到 appdelegate.m 中? 那也没有用。 我想它必须几乎不可能修复,否则一年不会过去,开发人员仍然没有解决它。 考虑到它让应用程序看起来有多糟糕,它显然也是要解决的首要问题。

FWIW,这就是我解决这个问题的方式。 我正在使用 LaunchScreen.xib 和 David-a 的解决方案:

UIView *loading = [[[NSBundle mainBundle] loadNibNamed:@"LaunchScreen" owner:self options:nil] objectAtIndex:0];
rootView.loadingView = loading;
rootView.loadingViewFadeDelay = 1;

此代码插入在下面

RCTRootView *rootView = [[RCTRootView alloc] etc etc etc...]

如果我用 nicklockwood 的示例代码替换该代码,白色闪光会返回。

哇! 好的,一个工作。 谢谢格里塔斯!

@grittathh @hasen6啊,好的。 我记错了,如果它的大小为零,loadingView 会自动调整大小以适应屏幕,但显然情况并非如此¯_(ツ)_/¯。

@hasen6这是应该可以工作的代码的修改版本(xib 解决方案也很好,但如果您只是使用黑屏,则是多余的)。

rootView.loadingView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
rootView.loadingView.backgroundColor = [UIColor blackColor];
rootView.loadingViewFadeDelay = 0.5; // measured in seconds

注意:对于 loadingViewFadeDelay 来说,1 是一个相当大的值,因为这意味着用户必须在应用程序启动前多等待一秒钟。 我建议将它设置为您可以摆脱的最低值(0.25 是默认值,这对大多数应用程序来说都很好)。

是的,我发现 1 有点长,而且我错过了我的一个应用程序的开场动画。我发现即使是 0.1 也可以。谢谢你的帮助。

我同意@hasen6 。 在生成 React Native 应用程序后,用户必须立即潜入 Objective-C ( AppDelegate.m ) 并立即调整一些代码,这似乎有点奇怪。 React Native 是否可以生成带有此修复程序的代码? 或者从 JavaScript(或声明性配置语言)为开始屏幕配置引入更抽象的解决方案?

@johanatan具有讽刺意味的是,React Native 的两个最大和持续时间最长的问题与某种白色闪光有关。 此错误和图像上的白色闪烁。

当我使用 LaunchScreen xib 时,它往往会更大,有什么解决方案吗?

什么往往更大?

UIView *loading = [[[NSBundle mainBundle] loadNibNamed:@"LaunchScreen" owner:self options:nil ] obje ctAtIndex:0 ];
rootView.loadingView = 加载;

加载 UI 视图,它似乎没有调整大小,它假设与我的启动画面相同,即我的 LaunchScreen.xib

我正在使用尺寸类和约束 BTW

@akoshdee是正确的 - 您需要明确设置视图大小以匹配屏幕大小。 使用

loading.frame = [UIScreen mainScreen].bounds;

已经改变了框架但仍然不起作用

安卓有什么解决方案吗?

@ajoshdee loadingView.frame = [UIScreen mainScreen].bounds;分配对我不起作用,但这样做了: loadingView.frame = self.window.bounds;

这就是我正在使用的:

NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"LaunchScreen" owner:self options:nil];
UIImageView *loadingView = [nibObjects objectAtIndex:0];
loadingView.frame = self.window.bounds;
rootView.loadingView = loadingView;

你好! 我设置颜色来反应视图:
rootViewController.view.backgroundColor = [UIColor blackColor];

@py110 @ajwhite

Android 解决方案非常简单,以至于我对自己花了多长时间才弄明白这一点感到恼火。

它涉及一个 3 阶段的启动画面。

https://github.com/mehcode/rn-splash-screen/issues/1

我有一个类似的实现@mehcode——不过我喜欢你在这里得到的东西。 我一直在寻找访问 RN Instance manager 的方法,没有看到有getReactNativeHost()调用,很高兴知道。

我做了以下,(不高兴)

  1. SplashActivity在应用程序打开时开始
  2. 立即打开MainActivityfinish()
  3. MainActivity开始SplashActivity并带有一个标志,表明它处于“前景模式”,一旦它开始在MainActivity上方显示飞溅。 一小段时间后, SplashActivity自行关闭,显示该应用程序。

@ajwhite

谢谢。 效果非常流畅。

在我当前的项目中,我确实将ReactActivity复制到我的代码库中,并将mReactInstanceMangager设为保护而不是私有。

在 react-native 0.29(应该在评论中说)中,react native 团队给了我们一个公共方法getReactNativeHost()来进入它。

ReactNativeHost容器是一个绝妙的举动。 这正是我遇到的问题——无法从 MainActivity 挂钩到生命周期。

感兴趣的参考: https :

要添加到此...

我发现的一个解决方案是为rootView分配背景颜色,但使用[UIColor colorWithPatternImage:img]

这不需要任何延迟来确保它在完全加载之前保持可见。

下面是一个完整的片段(并使用@dvine-multimedia 提供的提示),它将为设备找到所需的 LaunchImage:

NSArray *allPngImageNames = [[NSBundle mainBundle] pathsForResourcesOfType:@"png" inDirectory:nil];
  for (NSString *imgName in allPngImageNames){
    if ([imgName containsString:@"LaunchImage"]){
      UIImage *img = [UIImage imageNamed:imgName];

      if (img.scale == [UIScreen mainScreen].scale && CGSizeEqualToSize(img.size, [UIScreen mainScreen].bounds.size)) {
        rootView.backgroundColor = [UIColor colorWithPatternImage:img];
      }
  }
}

LaunchImage 现在保持可见,直到 react-native 包完全加载。

我几乎没有机会尝试了这次对话中的所有代码块,但这个代码块运行良好。
谢谢@dbonner1987

安卓有什么解决方案吗?

@pareekkhushboo77 https://github.com/mehcode/rn-splash-screen/blob/master/docs/android.md


@sercanov @dbonner1987这也使用上面提到的 iOS 方法来执行 javascript 启动屏幕。

@arnemart谢谢,在 RN 0.30.0 中仍然有效。 我不得不删除我的应用程序并重新安装它。 它第一次有白色闪光,但之后就没有了。

@nicklockwood是否有某种回调我可以用来知道何时加载实际的 javascript。 这样做的原因是,当我的应用程序在页面之间导航时,有一些透明度,其中 rootView.backgroundColor 在视图的背景中可见。 我在抽屉打开过渡期间使用的抽屉插件也遇到了类似的问题。
所以我想做一些类似的事情:

  • 在加载过程中使用@dbonner1987上面的方法将 rootView 背景颜色设置为启动器图像。
  • 当 javascript 完成加载并且第一个导航路线开始时(或沿着这些路线的东西)
  • 将 rootView 背景颜色设置回白色。

所以我基本上需要一个回调来知道加载何时完成。

@UKDeveloper99请参考我在上面多次链接的文档。 有这样的回调可用。

https://github.com/mehcode/rn-splash-screen/blob/master/docs/android.md

@mehcode 太棒了,谢谢!!

任何人都有关于如何实现一个LaunchScreen.storyboard建议,该

@ajoshdee我遇到了类似的问题,其中视图最终比屏幕大得多。 不确定它是否相关,但我在LaunchScreen.xib使用了 AutoLayout。

我还需要设置

launchScreenView.autoresizingMask = UIViewAutoresizingNone;

使其大小合适。

所以https://github.com/facebook/react-native/issues/1402#issuecomment -166963438 加上上面的那一行

您还可以更新启动颜色以替换 appdelegate.m 中的这一行:

rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];

通过这一行:
rootView.backgroundColor = [[UIColor alloc] initWithRed:0.94 green:0.90 blue:0.89 alpha:1.0];

并在这个网站上找到你想要的颜色

有人在 Android 上解决了这个问题吗?

这是一个适用于 ios 和 android 的解决方案: https :
我将启动画面隐藏在我的 app.tsx(入口点)的渲染函数中并显示相同的图像,直到我的所有 https 请求都完成。

我的代码:
``
公共渲染()
{
SplashScreen.hide();

   //after everything has finished loading - show my app.
   if (this.state.isFinishedloading) 
    {
        return (
            <this.navigator screenProps={{ ...providers }} />
        );
    }

  // Until then show the same image as the splash screen with an ActivityIndicator.
    return (
       <View style={{ flex: 1 }}>
          <Image style={styles.image} source={require('../assets/img/splash.png')} >
            <ActivityIndicator  style={styles.indicator} color="#fff"></ActivityIndicator>
          </Image>
       </View>
    );

}

``

如果我将故事板用于启动画面,有什么解决方案吗? 我不再有每个维度的启动屏幕图像。

AppDelegate.m内的 iOS 原生 React 中,通过相应地编写您的 RGB 颜色代码来更改以下行:

rootView.backgroundColor = [[UIColor alloc] initWithRed:52.0f/255.0f green:73.0f/255.0f blue:94.0f/255.0f alpha:1];

对于红色更改数字 52
对于绿色更改数字 73
对于蓝色更改数字 94

_注意:我使用的是 react native v0.51.0_

安卓还是没有解决方案吗?

@otoinsa请参阅https://github.com/facebook/react-native/issues/1402#issuecomment -339336380。 还有一些其他启动画面库也适用于例如https://github.com/crazycodeboy/react-native-splash-screen。

关于用作 LaunchScreen 的故事板有什么建议吗?

我的方法是这样的(但应用程序在启动时崩溃)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSURL *jsCodeLocation;
    [Fabric with:@[[Crashlytics class]]];

    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];

    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                moduleName:@"MyApp"
                                initialProperties:nil
                                launchOptions:launchOptions];
    rootView.backgroundColor = [UIColor clearColor];

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

//  UIViewController *rootViewController = [UIViewController new];

  UIStoryboard *storyboard = self.window.rootViewController.storyboard;
  UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:@"the_storyboard_id"];

    rootViewController.view = rootView;
    self.window.rootViewController = rootViewController;
    [self.window makeKeyAndVisible];
    return YES;
}

该应用程序崩溃并出现以下错误:

2018-03-30 11:21:04.995601+0530 MyApp[6119:101967] Running application MyApp ({
    initialProps =     {
    };
    rootTag = 1;
})
2018-03-30 11:21:05.014109+0530 MyApp[6119:101967] *** Assertion failure in -[UIApplication _runWithMainScene:transitionContext:completion:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.33.6/UIApplication.m:3529
2018-03-30 11:21:05.090174+0530 MyApp[6119:101967] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Application windows are expected to have a root view controller at the end of application launch'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000011170f12b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x0000000110001f41 objc_exception_throw + 48
    2   CoreFoundation                      0x00000001117142f2 +[NSException raise:format:arguments:] + 98
    3   Foundation                          0x000000010faa2d69 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
    4   UIKit                               0x000000010d838051 -[UIApplication _runWithMainScene:transitionContext:completion:] + 3102
    5   UIKit                               0x000000010dc016f8 __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 924
    6   UIKit                               0x000000010dfd74c8 +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
    7   UIKit                               0x000000010dc012f1 -

谢谢。

取代

UIStoryboard *storyboard = self.window.rootViewController.storyboard;

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];

现在应用程序启动,但我得到黑色背景。

或者你可以使用 https://github.com/crazycodeboy/react-native-splash-screen 它更容易:)

此页面是否有帮助?
0 / 5 - 0 等级