React-native: [Initialisation] Écran de lancement flash blanc

Créé le 26 mai 2015  ·  138Commentaires  ·  Source: facebook/react-native

Je me demande simplement s'il existe une bonne pratique concernant LaunchScreen. La raison pour laquelle je pose cette question est que si l'on ajoute LaunchScreen, il y a un flash blanc avant que le natif de réaction ne démarre et ne charge l'application. Y a-t-il un moyen d'empêcher cela?

AsyncStorage Locked

Commentaire le plus utile

Pour ajouter à cela...

Une solution que j'ai trouvée consistait à attribuer au rootView une couleur d'arrière-plan mais à utiliser [UIColor colorWithPatternImage:img] .

Cela ne nécessite aucun délai pour s'assurer qu'il reste visible jusqu'à ce qu'il soit complètement chargé.

Un extrait complet (et en utilisant l'astuce fournie par @dvine-multimedia) qui trouvera le LaunchImage souhaité pour l'appareil est ci-dessous :

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];
      }
  }
}

Le LaunchImage reste maintenant visible jusqu'à ce que le bundle de réaction natif soit complètement chargé.

Tous les 138 commentaires

@alinz ressemble- t-il à quelque chose comme https://www.dropbox.com/s/xq522ywqsd16vqe/example.mov?dl=0

@liubko Oui, c'est exactement ce dont je veux me débarrasser. Je n'ai pas encore appliqué le patch mais je le ferai ce soir.

@brentvatne : Je ne vois pas comment ce correctif

@oblador - ah, cela vous permettrait de faire une transition plus fluide en ayant la même couleur d'arrière-plan que l'écran de lancement au moment du "scintillement".

@vjeux - comment surmonter ce problème dans les applications FB ? J'ai remarqué que F8, qui si je comprends bien est 100% React Native, passe directement de l'écran de lancement à l'application. cc @nicklockwood

Il existe également un correctif (séparé) pour ce problème. Utilisez la nouvelle propriété loadingView de RCTRootView et définissez-la sur un UIImageView plein écran affichant votre image de lancement. Le code pourrait ressembler à ceci :

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

J'ai expérimenté un moyen de détecter automatiquement l'image de lancement et de la rendre complètement automatique, mais ce n'est pas encore vraiment prêt. Si ça vous intéresse, ça ressemble à ça :

// 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;
}

Une solution simple à ce que @nicklockwood a décrit consiste à charger l'écran de lancement xib si vous utilisez iOS 8+.

@ide J'utilise launchscreen xib. Je vois ma vue sur l'écran de lancement au moment du lancement, mais avant que mon application ne démarre, je vois une vue blanche (flash).

@alinz , je crois que @ide signifie utiliser votre xib launchscreen pour définir le RCTRootView loadingView (ce que vous devrez toujours faire manuellement). Il n'y a pas (encore) de support automatique pour le faire.

Pour clarifier, iOS masque votre écran de lancement au moment où React _commence_ le chargement. Pour éviter de voir un écran vide, vous devrez prolonger la durée d'affichage de l'écran de lancement en affichant manuellement la même vue que la vue de chargement de RCTRootView.

Merci @nicklockwood pour les éclaircissements. C'était mon mal. :)

Avec la permission de http://stackoverflow.com/a/29115477/255765, je me suis retrouvé avec ceci :

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;
      }
    }
  }

Semble fonctionner.

+1 pour une manière standard/documentée.

@dvine-multimedia est-ce que cela fonctionne mieux que l'extrait de code que j'ai fourni ci-dessus ?

@ myusuf3

@nicklockwood En fait, ils font à peu près la même chose. Quand j'ai commencé à me pencher là-dessus, je n'ai probablement pas compris quoi faire de votre snappé par manque d'expérience xcode. Quand je suis finalement arrivé au point où j'ai compris quoi faire, je n'ai pas réalisé que tu étais déjà là. A côté de ça, je trouve personnellement "ma" solution un peu plus lisible. Mais c'est de l'esthétique pure.

@nicklockwood J'ai essayé votre code mais je vois toujours un flash blanc. J'ai créé une image de lancement à définir comme vue de chargement. l'image de lancement est la même que launchScreen.xib.

C'est la seule chose qui retient la sortie de notre application. J'apprécie vraiment toute aide à ce sujet.

Le flash apparaît-il après que l'image de lancement est masquée, ou l'image de lancement ne s'affiche-t-elle pas ? (Cela peut être difficile à déterminer simplement en regardant - changez temporairement l'image de lancement en quelque chose comme un rectangle rouge solide pour être sûr).

@nicklockwood J'ai essayé de changer la couleur entre le fichier xib et l'image launchScreen. Je voyais toujours ce flash.

Mon code ressemble à ceci :

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

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

J'ai supprimé les deux dernières lignes loadViewFadeDelay et la durée maintenant et il semble que le problème soit résolu. Je ne vois aucun flash. Belle transition en douceur.

@ chirag04 Je viens de l'essayer avec un exemple de projet et je n'ai pas vu le flash :(

voici ce que j'ai fait

  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;

D'accord. en creusant plus profondément, il semble que le flash soit peut-être parce que mon application ne rend rien jusqu'à ce qu'une valeur soit chargée à partir d'asyncstore.

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

Je pense que le loadingView pense que le js a terminé le rendu et cache le loadingView. Cependant js vient de terminer le rendu avec ce return null

@nicklockwood @alinz Je tire juste en l'air. peut-être pas la vraie raison. Qu'en pensez-vous.

Une autre chose que j'ai remarquée est que si je définis ces valeurs de loadingViewFadeDelay etc sur 0,30 ou plus, la transition est très très fluide. les valeurs par défaut sont de 0,25, ce qui est également lisse.

Le but du chargementFadeDelay est précisément de couvrir le scénario où votre application ne rend rien immédiatement, donc vous l'utilisez correctement.

Vous voudrez peut-être envisager de définir explicitement le chargementViewFadeDelay, au cas où la valeur par défaut changerait - et assurez-vous de tester sur le périphérique le plus lent que vous prenez en charge, au cas où le chargement prendrait plus de temps.

J'aime la solution @nicklockwood mais vous devez tenir compte de la latence du réseau qui ne peut pas être prédite.

Une autre solution consiste à définir l'état du composant sur une sorte de valeur par défaut pour indiquer à votre composant d'afficher une sorte de boîte de dialogue de chargement.

Cool. Je pense avoir la solution.

Que pensez-vous d'avoir 3 composants tous identiques.

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

Je ne sais pas comment le point 3 sera mis à l'échelle sur différents appareils. Voudriez-vous même suggérer cela?

Si le temps de démarrage dépend du réseau, je recommanderais certainement de dessiner immédiatement une vue "vide" au lieu d'espérer qu'elle se télécharge plus rapidement que le délai de fondu.

dépend de l'asyncstorage. pas de réseau

Que vous dépendiez du réseau ou non, je n'aime pas vraiment utiliser l'affichage de la base de temps. Il n'y a aucun moyen de garantir à 100% que l'heure que vous avez définie est exacte. Vous devez toujours afficher quelque chose à l'utilisateur pour indiquer que quelque chose se passe mais qu'il n'est pas prêt à s'afficher. Ce n'est qu'une suggestion.

D'accord. Le but de loadingView, comme l'image de chargement iOS standard, est juste de couvrir jusqu'à ce que votre application soit prête à afficher quelque chose, même si toute l'application est prête à afficher est un spinner de chargement.

Cela dit, la raison pour laquelle j'en ai fait une vue au lieu d'une image est que vous pouvez la rendre non statique. Vous pouvez ajouter un UIActivityIndicatorView au loadingView si vous le souhaitez.

Comment positionner l'image de lancement ? J'ai essayé d'ajuster l'origine du cadre, mais il le positionne toujours au centre, quelle que soit l'origine que j'ai utilisée. J'ai une petite image de la barre supérieure que je veux positionner en haut et étirée de gauche à droite.

Voilà ce que j'ai :

  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;

Ce n'est pas une image de lancement, c'est une _vue_ de lancement, vous pouvez donc positionner votre imageView dans une autre vue de conteneur et utiliser le conteneur comme vue de lancement :

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

Certes, je suppose que je pourrais faire en sorte que le wrapper remplisse l'espace de l'écran et positionne l'image en haut. Le wrapper sera automatiquement positionné au centre par le RootView il semble https://github.com/facebook/react-native/blob/757d6d204ae2d743634af64e3f78a4aad9d53f70/React/Base/RCTRootView.m#L191.

@Intellicode oui.

Je viens de casser mon application en production sur iphone 4s en utilisant le code de @dvine-multimedia. Le correctif consiste simplement à mettre une pause dans le if.

Encore un crash car containsString n'est pas disponible sur ios 7.

@nicklockwood se demande si la vue de chargement choisira automatiquement la meilleure résolution possible ?

loadingView ne choisit pas du tout d'image, il utilise simplement ce que vous transmettez. L'extrait que j'ai posté ci-dessus pour trouver le lancement sélectionnera cependant la résolution correcte pour l'appareil.

Cependant, votre extrait de code ne choisit pas celui qui a les bonnes dimensions. une solution pour ça ?

Utilisiez-vous ma solution ou celle de dvine? Quel modèle d'iPhone utilisez-vous ? Portrait ou paysage ?

lors de l'utilisation de dvine, il prend la bonne dimension. Avec votre solution, il y a un espace noir autour de l'image. Je suppose que l'espace noir est dû au fait qu'il capte l'image avec une mauvaise dimension.

Je suis sur iphone 6. portrait.

Voilà à quoi ça ressemble. Remarquez le fond blanc.

En utilisant le code suivant :

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

lrn_launch_screen

Ce n'était pas la solution que j'avais postée, c'était :

// 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;
}

Oh putain! J'aimerais lire attentivement votre commentaire. Votre solution fonctionne et elle est également facile à comprendre.

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:

C'est peut-être le truc de experimenting . Je ne sais pas comment je l'ai raté. Désolé mon mauvais.

Merci pour l'aide ici. Utilisera par défaut ce code dans la prochaine version. Semble couvrir tous les cas aussi. Pas besoin de paysage.

Heh, je suppose que je l'ai sous-vendu. J'aurais probablement dû dire "c'est ce que nous utilisons en production en ce moment, et cela semble fonctionner correctement" :-)

"c'est ce que nous utilisons en production en ce moment" nous aurait évité quelques 1 étoile sur l'App Store. haha. Pas de soucis. Il y a toujours une nouvelle version pour sauver le monde. :)

Fermer ce problème d'ailleurs?

Je vais fermer ce ticket car il a été entièrement discuté en détails, nous avons de bonnes solutions.

Juste pour que cela soit clair à 100% pour ceux qui utilisent un xib LaunchScreen, voici le code qui fera que cela fonctionnera :

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

Ajouter ces lignes à application didFinishLaunchingWithOptions méthode dans le AppDelegate.m fichier, juste au- dessus de la ligne qui dit return YES .

@arnemart pour être plus clair, cette méthode ne fonctionnera que pour ios 8+, n'est-ce pas ?

@arnemart Merci ! Fonctionne parfaitement .

Pour ceux qui utilisent un LaunchImage , vous devez définir à la fois frame et contentMode pour que l'image soit correctement mise à l'échelle :

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

Tout comme le commentaire de @arnemart , ajoutez ces lignes à la méthode application didFinishLaunchingWithOptions dans le fichier AppDelegate.m , au-dessus de la ligne qui dit return YES .

Bizarre. Sur RN v.0.11.4, l'application se lance d'abord avec un écran noir, puis LaunchScreen.xib avant de charger l'application. iOS 9 w / @arnemart est fix https://github.com/facebook/react-native/issues/1402#issuecomment -130236507. Des idées?

@irfaan essayez de changer window.backgroundColor en quelque chose comme [UIColor redColor], cela devrait nous dire si la couleur noire vient de la fenêtre ou autre chose.

self.window.backgroundColor = [UIColor redColor]; intérieur de didFinishLaunchingWithOptions n'a rien changé. Toujours noir avant le LaunchScreen.xib. Donc pas de la fenêtre, on dirait @nicklockwood

Comment me conseillez-vous de procéder au débogage ?

Il semble qu'iOS ne charge pas du tout votre launchScreen.xib tant que l'application n'est pas chargée (à ce stade, React l'affiche en tant que loadingView).

C'est peut-être une erreur de configuration dans Xcode ? Ou peut-être un bug dans iOS 9 ?

Avez-vous essayé sur un appareil, ou seulement le simulateur ?

Merci @nicklockwood - J'avais rencontré le problème sur l'appareil. L'a exécuté dans le simulateur et cela a parfaitement fonctionné, puis supprimé + exécuté sur l'appareil et cela fonctionne bien. Vraiment bizarre. Je posterai à nouveau si le problème réapparaît.

salut @genexliu , j'ai ajouté mon ensemble d'images "LaunchImage" à Images.xcassets/LaunchImage.launchimage/ mais ni le code que vous avez collé ni mon LaunchScreen.storyboard ne peuvent les trouver/les utiliser (les deux échouent silencieusement). Mon storyboard LaunchScreen se charge correctement car je vois sa couleur d'arrière-plan mais il n'affiche pas l'image référencée. Des idées?

De plus, la séquence de démarrage lors de l'exécution à partir de XCode semble normale, mais il semble y avoir une exécution supplémentaire de la séquence de démarrage/un flash blanc supplémentaire/etc lors de l'exécution de natal launch partir de la ligne cmd.

Il s'avère que mon problème avec le Storyboard ne trouvant pas le LaunchImage était apparemment un bogue avec XCode. J'ai modifié le paramètre de lancement en « utiliser le catalogue d'actifs », puis de nouveau en « utiliser le storyboard » et cela a commencé à fonctionner. Il n'est pas clair si le code de @genexliu fonctionne pour moi ou non, car loadingViewFadeDelay ne semble pas avoir d'effet.

Voici mon code :

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

pourtant, il n'y a pas de délai entre l'affichage LaunchImage du storyboard et mon React initial render .

@"Images/LaunchImage" ne me semble pas correct. C'est probablement juste @"LaunchImage"

Oh, oups, ouais. Vous avez raison. C'était une erreur de collage - l'une des permutations que j'ai essayées (mais pas la première).

Vérifiez également l'exemple de code dans mon commentaire ci-dessus d'il y a 3 mois - il existe de nombreux fichiers image de lancement pour différentes classes de périphériques.

Oh ! Tu avais raison. Après être revenu à LaunchImage cela fonctionne maintenant. Merci!

Quelqu'un peut-il m'indiquer une documentation à ce sujet pour Android ?

+1 pour Android

cc @dmmiller avons-nous une fonctionnalité loadingView sur Android ?

Salut, je rencontre le même problème, et bien que je vois qu'il existe des solutions publiées ici, je ne comprends pas où mettre ce code. D'après ce que j'ai compris, la solution consiste à modifier le code Objective-C, ce n'est pas quelque chose qui peut être fait dans React Native lui-même, n'est-ce pas ? Dans ce cas, où va le code posté ? Dans le fichier main.m à la racine du projet xcode ? Merci.

@CorpusCallosum le code doit aller dans le fichier AppDelegate.m, où le RCTRootView est configuré.

Merci @nicklockwood , je vais essayer ça.

Hé, ce code fonctionne pour moi maintenant, dans la mesure où je ne vois pas le flash blanc et que mon image est chargée dans cet écran initial, cependant, maintenant, mon application réelle ne se chargera pas ! Il reste juste sur cet écran de chargement, bien que je puisse voir dans ma console, l'application est chargée et en cours d'exécution, et même l'interaction fonctionne (appuyez et glissez), mais je ne peux pas du tout voir mon application, elle est juste bloquée sur cet écran initial. Une idée pourquoi ?

Voici mon code de mon fichier 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 Vous pouvez essayer de supprimer la ligne
rootView.loadingViewFadeDelay = 1000;
ou affinez la transition entre l'écran de démarrage et votre application avec sa valeur (je pense que les unités sont des secondes, pas des millisecondes, c'est pourquoi il semble "bloqué" sur le splash).
Si supprimer complètement la ligne ne fonctionne pas pour vous, essayez de définir des valeurs comprises entre 0 et 5 (vous pouvez également définir des valeurs non entières).

Travailler pour moi, merci les gars :)

Pour ceux qui veulent utiliser leur launchscreen xib comme loadingView, voici le code à insérer dans AppDelegate.m :

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

La dernière ligne est facultative, comme je l'ai mentionné ci-dessus, elle définit la durée pendant laquelle le chargementView restera avant de passer à l'application elle-même.

@david-a merci beaucoup pour ça ! Je suis confronté à cela depuis que j'ai commencé à tester React Native. ??

@david-a, @geriux : J'ai également dû définir launchScreenView.frame = CGRectZero; car mon LaunchScreen.xib avait une image d'arrière-plan avec le mode de contenu AspectFill et il n'était pas correctement mis à l'échelle. Je suis arrivé à la solution après quelques essais et erreurs, je ne sais pas ce qui cause cela.

@BasitAli oui, désolé, cela devrait être mieux documenté. Si vous définissez la taille de la vue sur une valeur différente de zéro, elle sera centrée sur l'écran. Si vous le mettez à zéro, il sera mis à l'échelle pour s'adapter à l'écran.

@david-a merci beaucoup ! Votre commentaire doit être inclus dans le passe-partout, ou au moins faire partie de la principale documentation native de React. Je ne sais pas pourquoi ce problème a été fermé en mars 2015, il existe toujours clairement dans la RN 0.20 en février 2016.

Ce serait bien si quelqu'un peut faire le PR pour le document.

Les conseils de vos gars m'aident beaucoup (sur IOS, fonctionne parfaitement), est-ce que quelqu'un a trouvé un moyen de résoudre ce problème sur Android ?

@weiyisheng , j'utilise @braco sur Android avec le correctif discuté ci-dessus sur iOS.

@braco @BasitAli OUI, ça

@BasitAli pourquoi ne pas l'utiliser sur iOS par curiosité ?

Mon application s'anime de manière transparente de l'écran de démarrage à l'écran de connexion (le logo se déplace vers le haut et les champs de connexion sortent). Le plugin rn-splashscreen disparaît, ce qui ne va pas très bien avec mon animation. J'ai dû l'utiliser sur Android car je n'avais pas d'autre choix.

@BasitAli, il semble que le plugin react-native-splashscreen obéisse au paramètre rootView.loadingViewFadeDuration , à condition que vous le définissiez après l'avoir attaché, cela devrait donc désactiver le fondu :

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

Existe-t-il un moyen de supprimer ce petit message en haut indiquant « Chargement à partir du fichier pré-groupé » ?

@rclai définit le schéma à publier

Ah ! Merci!

Existe-t-il une solution native de réaction pour l'écran de démarrage des deux plates-formes ? La saisie des fichiers internes des deux plates-formes rend inutile l'utilisation de react-native .. Réponse simple s'il vous plaît. Merci

@rclai

Existe-t-il un moyen de supprimer ce petit message en haut indiquant « Chargement à partir du fichier pré-groupé » ?

Cela n'est pas affiché en mode de publication, uniquement en mode de débogage. Si vous souhaitez également le masquer en mode débogage, vous pouvez le masquer en mettant [RCTDevLoadingView setEnabled:NO]; dans votre AppDelegate.

@nicklockwood Bonjour, est-ce correct ? Sinon, que dois-je modifier/supprimer ?

  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 me semble juste. Si vous voyez toujours un flash au démarrage, essayez de régler

rootView.loadingViewFadeDelay

À une valeur plus grande (c'est en secondes - la valeur par défaut est 0,25)

ÉDITER:

Cette ligne

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

Devrait probablement être juste

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

Merci, dans quel dossier dois-je ajouter ces images ? Ai-je besoin de Contents.json supplémentaire pour cela ou non ? J'ai eu plusieurs erreurs dans ce code commençant par
(https://cloud.githubusercontent.com/assets/10398337/13778676/e01e3d32-eabf-11e5-95bf-d7a1205a5ca1.png)
Fixer:

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

@TeodorKolev Xcode a une interface graphique pour les ajouter. Cliquez sur Images.xcassets, puis cliquez sur le bouton + et sélectionnez « Icônes d'application et images de lancement » > « Nouvelle image de lancement iOS ».

screen shot 2016-03-15 at 13 47 48

@TeodorKolev pour corriger les erreurs, vous devez ajouter

#import "RCTUtils.h"

Dans votre AppDelegate.

Merci beaucoup, mais je veux voir l'écran de démarrage jusqu'à ce que mon URL WebView se charge complètement, et maintenant cela ne fonctionne pas comme ça. Respecter!

@nicklockwood Avez-vous un remède pour celui-ci ?

Quelle est la méthode actuelle pour résoudre ce problème ? Comme cela fait un an et quelques mois que le problème est apparu, je doute qu'il soit un jour résolu, donc je me demande quel est le remède actuel. Quel fichier doit être modifié et quel code doit être modifié ?

Edit : j'utilise juste un écran noir avec le launchscreen.xib mais à mi-chemin, il devient blanc avant que l'application ne se charge complètement.

@ hasen6 le problème a déjà été résolu, mais il y a du travail à faire de la part du développeur.

Comme indiqué dans les commentaires ci-dessus, vous devez définir le rootView.loadingView avec du contenu à afficher à la place de l'écran blanc, et ajuster le rootView.loadingViewFadeDelay pour vous assurer que la vue de chargement n'est pas masquée avant votre l'application a fini de se charger.

Si vous souhaitez simplement afficher un écran noir, vous n'aurez peut-être pas besoin de vous soucier d'un loadingView et de définir simplement le rootView.backgroundColor sur noir, mais vous devrez expérimenter.

J'ai changé rootView.backgroundColor = [UIColor clearColor]; en rootView.backgroundColor = [UIColor blackColor] ; but it didn't make any difference. Doing a search in XCode for rootView.loadingView` n'a renvoyé aucun résultat.

@ hasen6, vous devez déterminer d'où vient la couleur blanche - il se peut qu'il y ait une vue à l'intérieur de votre application JS qui soit blanche et qui s'affiche pendant un certain temps avant le chargement du contenu.

loadingView est une propriété de RCTRootView , dont vous avez probablement une instance dans votre AppDelegate. Le code réel rootView.loadingView n'apparaîtra pas dans votre Xcode à moins que vous ne l'ayez ajouté vous-même. Voici un exemple de la façon dont vous pouvez l'utiliser :

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

Mon application n'est blanche nulle part. Toutes mes applications affichent le même écran blanc au chargement après l'affichage de l'écran de lancement, donc je suis sûr que ce n'est pas un problème avec mes applications.

Je dois donc ajouter ce code dans le fichier appdelegate.m ? Cela n'a pas fonctionné non plus. Je suppose que cela doit être presque impossible à réparer, sinon un an ne se serait pas écoulé sans que les développeurs ne l'aient toujours résolu. Compte tenu de la mauvaise apparence des applications, ce serait évidemment en tête de liste à résoudre également.

FWIW, voici comment je résous ce problème. J'utilise LaunchScreen.xib et la solution de David-a :

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

Ce code est inséré juste en dessous

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

Si je remplace ce code par l'exemple de code de Nicklockwood, le flash blanc revient.

Ouah ! Ok celui-là fonctionne. Merci grittathh !

@grittathh @hasen6 ah, d'accord. Je me suis mal souvenu que loadingView était automatiquement dimensionné pour s'adapter à l'écran s'il a une taille nulle, mais apparemment cela n'a jamais été le cas ¯_(ツ)_/¯.

@ hasen6 voici une version modifiée du code qui devrait fonctionner (la solution xib convient également, mais redondante si vous utilisez simplement un écran noir).

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

Remarque : 1 est une valeur assez élevée pour le chargement de ViewFadeDelay, car cela signifie que les utilisateurs doivent attendre une seconde supplémentaire avant que l'application ne démarre. Je suggère de le régler sur la valeur la plus basse avec laquelle vous pouvez vous en sortir (0,25 est la valeur par défaut, ce qui convient à la plupart des applications).

Oui, j'ai trouvé que 1 était un peu long et il me manquait l'animation d'ouverture sur l'une de mes applications. J'ai même trouvé que 0,1 était bien. Merci de votre aide.

Je suis d'accord avec @hasen6 . Il semble certainement un peu étrange que les utilisateurs doivent immédiatement plonger dans Objective-C ( AppDelegate.m ) et modifier du code immédiatement après avoir généré une application React Native. Ne serait-il pas possible pour React Native de générer du code avec ce correctif déjà intégré ? Ou pour introduire une solution plus abstraite pour la configuration de l'écran de démarrage à partir de JavaScript (ou d'un langage de configuration déclaratif) ?

@johanatan Ironiquement, les deux problèmes les plus importants et les plus durables avec React Native sont liés à une sorte de flash blanc. Cette erreur et le flash blanc sur les images.

Lorsque j'utilise mon LaunchScreen xib, il a tendance à être plus gros, des solutions ?

Qu'est-ce qui a tendance à être plus gros ?

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

la vue de chargement de l'interface utilisateur, elle ne semble pas se redimensionner, elle est supposée être la même que mon écran de démarrage qui est mon LaunchScreen.xib

J'utilise des classes de taille et des contraintes BTW

@akoshdee c'est correct - vous devrez définir explicitement la taille de la vue pour qu'elle corresponde à la taille de l'écran. Utilisant

loading.frame = [UIScreen mainScreen].bounds;

déjà changé le cadre mais ne fonctionne toujours pas

n'importe quelle solution pour android?

@ajoshdee La loadingView.frame = [UIScreen mainScreen].bounds; n'a pas fonctionné pour moi mais cela a fonctionné : loadingView.frame = self.window.bounds;

Voici ce que j'utilise :

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

Salut! J'ai mis la couleur pour réagir à la vue :
rootViewController.view.backgroundColor = [UIColor blackColor];

@py110 @ajwhite

La solution Android est bêtement simple au point d'être ennuyé contre moi-même pendant combien de temps il a fallu pour la comprendre.

Il s'agit d'un écran de démarrage en 3 étapes.

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

J'ai eu une implémentation similaire @mehcode -- j'aime ce que vous avez ici cependant. J'ai cherché un moyen d'accéder au gestionnaire d'instances RN, je n'ai pas vu qu'il y avait un appel getReactNativeHost() , très bon à savoir.

J'avais fait ce qui suit, (pas content de ça)

  1. SplashActivity démarré à l'ouverture de l'application
  2. Ouvre immédiatement les MainActivity et finish()
  3. MainActivity démarre le SplashActivity avec un drapeau indiquant qu'il est en "mode premier plan" dès qu'il commence à afficher le splash au-dessus du MainActivity . Après une courte période de temps, le SplashActivity ferme en révélant l'application.

@ajwhite

Merci. L'effet est très doux.

Dans mes projets actuels, j'ai littéralement copié ReactActivity dans ma base de code et j'ai rendu le mReactInstanceMangager protégé au lieu de privé.

Dans react-native 0.29 (aurait dû le dire dans le commentaire), l'équipe de react native nous a donné une méthode publique getReactNativeHost() pour y entrer.

Ce conteneur ReactNativeHost est une initiative brillante. C'est exactement le problème que j'ai rencontré - ne pas être en mesure de se connecter au cycle de vie à partir de MainActivity.

Réf pour les intéressés : https://github.com/facebook/react-native/commit/49f20f41546e3ba8e7fe43c84c4c701684d0434d#diff -1346852de0c7f8466a36d42de50ec808R20

Pour ajouter à cela...

Une solution que j'ai trouvée consistait à attribuer au rootView une couleur d'arrière-plan mais à utiliser [UIColor colorWithPatternImage:img] .

Cela ne nécessite aucun délai pour s'assurer qu'il reste visible jusqu'à ce qu'il soit complètement chargé.

Un extrait complet (et en utilisant l'astuce fournie par @dvine-multimedia) qui trouvera le LaunchImage souhaité pour l'appareil est ci-dessous :

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];
      }
  }
}

Le LaunchImage reste maintenant visible jusqu'à ce que le bundle de réaction natif soit complètement chargé.

J'ai essayé presque tous les blocs de code de cette conversation sans aucune chance, mais celui-ci a parfaitement fonctionné.
Merci @dbonner1987 !

une solution pour android ?

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


@sercanov @dbonner1987 Cela utilise également l'approche mentionnée ci-dessus pour iOS pour faire l'écran de lancement javascript.

@arnemart Merci, fonctionne toujours un peu dans RN 0.30.0. J'ai dû supprimer mon application et la réinstaller. Il a eu le flash blanc la première fois, mais aucun après cela.

@nicklockwood Existe-t-il une sorte de rappel que je peux utiliser pour savoir quand le javascript est chargé. La raison en est que lorsque mon application navigue entre les pages, il y a une certaine transparence où rootView.backgroundColor est visible en arrière-plan de la vue. J'ai également un problème similaire avec le plugin Drawer que j'utilise pendant la transition d'ouverture du tiroir.
J'aimerais donc faire quelque chose comme :

  • Définissez la couleur d'arrière-plan rootView sur l'image du lanceur, en utilisant l' approche de @dbonner1987 ci-dessus pendant le processus de chargement.
  • Lorsque le javascript a fini de se charger et que le premier itinéraire de navigation commence (ou quelque chose du genre)
  • Redéfinissez la couleur d'arrière-plan de rootView sur blanc.

J'ai donc essentiellement besoin d'un rappel pour savoir quand le chargement est terminé.

@UKDeveloper99 Veuillez vous référer à la documentation que j'ai liée ci-dessus à quelques reprises. Un tel rappel est disponible.

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

@mehcode c'est parfait merci !!

Quelqu'un a-t-il des suggestions sur la façon d'implémenter un LaunchScreen.storyboard qui s'éteint une fois le bundle chargé ? Actuellement, il s'affiche pendant une durée fixe, puis je vois un écran blanc, puis l'application charge RN 34.1 xcode 8

@ajoshdee J'ai eu des problèmes similaires où la vue a fini par être beaucoup plus grande que l'écran. Je ne sais pas si c'est lié, mais j'utilisais AutoLayout dans mon LaunchScreen.xib .

j'avais besoin de régler aussi

launchScreenView.autoresizingMask = UIViewAutoresizingNone;

Pour l'amener à la bonne taille.

Donc https://github.com/facebook/react-native/issues/1402#issuecomment -166963438 avec cette ligne ajoutée ci-dessus

Vous pouvez également mettre à jour la couleur de lancement en remplaçant cette ligne dans appdelegate.m :

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

par cette ligne :
rootView.backgroundColor = [[UIColor alloc] initWithRed:0.94 green:0.90 blue:0.89 alpha:1.0];

et trouvez la couleur que vous voulez avec ce site

Quelqu'un a-t-il réussi à résoudre ce problème sur Android ?

Voici une solution pour iOS et Android : https://github.com/mehcode/rn-splash-screen .
J'ai caché l'écran de démarrage dans la fonction de rendu de mon app.tsx (le point d'entrée) et j'ai montré la même image jusqu'à ce que toutes mes requêtes https soient terminées.

Mon code :
```
rendu public()
{
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>
    );

}

```

Existe-t-il une solution à cela si j'utilise un storyboard pour l'écran de démarrage ? Je n'ai plus mes images d'écran de lancement pour chaque dimension.

Dans React Native pour iOS dans AppDelegate.m modifiez la ligne suivante en écrivant vos codes de couleur RVB en conséquence :

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

Pour ROUGE changer le chiffre 52
Pour le VERT changer le nombre 73
Pour BLEU changer le nombre 94

_Remarque : j'utilise React Native v0.51.0_

Il n'y a toujours pas de solution pour Android ?

@otoinsa voir la réponse ci-dessus https://github.com/facebook/react-native/issues/1402#issuecomment -339336380 par @neomib. Il existe d'autres bibliothèques d'écrans de démarrage qui fonctionnent tout aussi bien pour, par exemple, https://github.com/crazycodeboy/react-native-splash-screen.

Une suggestion sur le storyboard utilisé comme LaunchScreen ?

Mon approche était comme ça (mais l'application plante au lancement)

- (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;
}

l'application plante avec l'erreur suivante :

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 -

Merci.

remplacé

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

avec

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

maintenant l'application démarre mais j'obtiens un fond noir.

Ou vous pouvez utiliser https://github.com/crazycodeboy/react-native-splash-screen c'est beaucoup plus facile :)

Cette page vous a été utile?
0 / 5 - 0 notes