React-native: [Inicialização] Tela inicial flash branco

Criado em 26 mai. 2015  ·  138Comentários  ·  Fonte: facebook/react-native

Só estou me perguntando se existe uma boa prática sobre LaunchScreen. A razão pela qual estou perguntando isso é, se alguém adicionar LaunchScreen, há um flash branco antes de o reagente nativo entrar em ação e carregar o aplicativo. Existe alguma maneira de evitar isso?

AsyncStorage Locked

Comentários muito úteis

Para adicionar a isso ...

Uma solução que encontrei foi atribuir a rootView uma cor de fundo, mas usar [UIColor colorWithPatternImage:img] .

Isso não requer atrasos para garantir que ele permaneça visível até que esteja totalmente carregado.

Um snippet completo (e usando a dica fornecida por @ dvine-multimedia) que encontrará o LaunchImage desejado para o dispositivo está abaixo:

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

O LaunchImage agora permanece visível até que o pacote reagente nativo seja totalmente carregado.

Todos 138 comentários

@liubko Sim, é exatamente disso que eu quero me livrar. Eu não apliquei o patch ainda, mas vou fazer isso hoje à noite.

@brentvatne : Não vejo como esse patch consertaria esse problema (se sou cego / estúpido, por favor me perdoe :-). O problema é que há um momento entre o momento em que o aplicativo foi iniciado e o React ainda está funcionando. O ideal é que o LaunchScreen seja exibido até que o React seja concluído e totalmente renderizado, como acontece em um aplicativo "totalmente nativo".

@oblador - ah, isso permitiria que você fizesse uma transição mais suave, tendo a mesma cor de fundo da tela de inicialização no momento de "oscilação".

@vjeux - como você @nicklockwood

Também existe uma correção (separada) para esse problema. Use a nova propriedade loadingView de RCTRootView e defina-a para tela inteira UIImageView mostrando sua imagem de lançamento. O código pode ser parecido com este:

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

Tenho experimentado uma maneira de detectar automaticamente a imagem de inicialização e torná-la totalmente automática, mas ainda não está realmente pronta. Se você estiver interessado, é assim:

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

Uma solução fácil para o que @nicklockwood descreveu é carregar a tela de inicialização xib se você estiver no iOS 8+.

@ide Estou usando o xib da tela de lançamento. Eu vejo minha tela lauch no momento do lançamento, mas antes que meu aplicativo seja inicializado, eu vejo uma visão branca (flash).

@alinz , acredito que @ide significa usar sua tela de inicialização xib para definir o loadingView RCTRootView (que você ainda precisará fazer manualmente). Não há suporte automático para fazer isso (ainda).

Para esclarecer, o iOS oculta sua tela de inicialização no momento em que o React _begins_ é carregado. Para evitar ver uma tela em branco, você precisará estender o tempo em que a tela inicial é exibida, mostrando manualmente a mesma visualização que o loadingView do RCTRootView.

Obrigado @nicklockwood pelo esclarecimento. Esse foi o meu mal. :)

Cortesia de http://stackoverflow.com/a/29115477/255765 Acabei com isto:

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

Parece funcionar.

1 para uma forma padrão / documentada.

@ dvine-multimedia isso funciona melhor do que o trecho de código que forneci acima?

@ myusuf3

@nicklockwood Na verdade, eles fazem

@nicklockwood Tentei seu código, mas ainda vejo um flash branco. Criei uma imagem de lançamento para definir como visualização de carregamento. a imagem de inicialização é igual a launchScreen.xib.

Esta é a única coisa que impede o lançamento de nosso aplicativo. Agradeço qualquer ajuda nisso.

O flash está aparecendo após a imagem de inicialização ser ocultada ou a imagem de inicialização não aparece? (Isso pode ser difícil de determinar apenas olhando - mude a imagem inicial para algo como um retângulo vermelho sólido temporariamente para ter certeza).

@nicklockwood Eu tentei mudar a cor entre o arquivo xib e a imagem launchScreen. Eu ainda estava vendo aquele flash.

Meu código é parecido com este:

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

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

Removi as duas últimas linhas loadingViewFadeDelay e duração agora e parece que o problema foi resolvido. Eu não vejo nenhum flash. Ótima transição suave.

@ chirag04 Acabei de experimentar com o projeto de amostra e não vi o flash :(

aqui está o que eu fiz

  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;

OK. cavando mais fundo, parece que o flash talvez porque meu aplicativo não renderiza nada até que um valor seja carregado do asyncstore.

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

Acho que o loadingView pensa que o js terminou de renderizar e esconde o loadingView. No entanto, js acabou de renderizar com aquele return null

@nicklockwood @alinz Estou apenas atirando para o

Também uma coisa que notei é que se eu definir os valores de loadingViewFadeDelay etc para 0,30 ou mais, a transição é muito suave. os padrões são 0,25, o que também é normal.

O objetivo do loadingFadeDelay é precisamente cobrir o cenário onde seu aplicativo não renderiza nada imediatamente, então você está usando-o corretamente.

Você pode querer considerar a configuração de loadingViewFadeDelay explicitamente, no caso de o padrão mudar - e certifique-se de testar no dispositivo mais lento que você suporta, caso demore mais para carregar.

Eu gosto da solução @nicklockwood , mas você deve considerar a latência da rede que não pode ser prevista.

Uma outra solução é definir o estado do componente para algum tipo de valor padrão para dizer ao seu componente para exibir algum tipo de caixa de diálogo de carregamento.

Legal. Acho que tenho a solução.

O que vocês acham de ter 3 componentes todos iguais.

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

Não tenho certeza de como o ponto 3 será escalonado em dispositivos diferentes. Vocês ao menos sugeririam isso?

Se o tempo de inicialização depende da rede e então teste, eu definitivamente recomendo desenhar uma visualização "vazia" imediatamente, em vez de esperar que o download seja mais rápido do que o retardo de enfraquecimento.

depende do armazenamento assíncrono. sem rede

Esteja você dependendo da rede ou não, eu realmente não gosto de usar a exibição de base de tempo. Não há como garantir 100% de que o tempo que você definiu está correto. Você deve sempre exibir algo para o usuário para indicar que algo está acontecendo, mas não está pronto para ser exibido. Isto é apenas uma sugestão.

Acordado. O objetivo do loadingView, como a imagem de carregamento padrão do iOS, é apenas cobrir até que seu aplicativo esteja pronto para exibir algo, mesmo se todo o aplicativo estiver pronto para exibir seja um spinner de carregamento.

Dito isso, a razão pela qual eu criei uma visualização em vez de uma imagem é para que você possa torná-la não estática. Você pode adicionar um UIActivityIndicatorView ao loadingView, se desejar.

Como a imagem de lançamento pode ser posicionada? Tentei ajustar a origem do quadro, mas sempre o posiciona no centro, independentemente da origem que usei. Tenho uma pequena imagem da barra superior que desejo posicionar no topo e esticada da esquerda para a direita.

Isso é o que eu tenho:

  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;

Não é uma imagem de lançamento, é uma _view_ de lançamento, então você pode posicionar sua imageView dentro de outra visualização de contêiner e usar o contêiner como visualização de lançamento:

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

É verdade, suponho que poderia fazer o wrapper preencher o espaço da tela e posicionar a imagem no topo. O wrapper será automaticamente posicionado no centro pelo RootView, parece https://github.com/facebook/react-native/blob/757d6d204ae2d743634af64e3f78a4aad9d53f70/React/Base/RCTRootView.m#L191.

@Intellicode yes.

Acabei de quebrar meu aplicativo em produção no iphone 4s usando o código de @dvine-multimedia. corrigir é apenas colocar uma pausa no if.

Mais uma falha porque containsString não está disponível no ios 7.

@nicklockwood está se perguntando se a visualização de carregamento escolherá automaticamente a melhor resolução possível?

O loadingView não escolhe uma imagem, ele apenas usa o que você passa. O trecho que postei acima para encontrar a página de inicialização irá selecionar a resolução correta para o dispositivo.

Porém, seu snippet não está escolhendo aquele com as dimensões corretas. alguma correção para isso?

Você estava usando a minha solução ou a do dvine? Qual modelo de iPhone você está usando? Retrato ou paisagem?

ao usar o dvine, ele pega a dimensão certa. Com a nossa solução é ter um espaço preto ao redor da imagem. Presumo que o espaço preto é porque ele pega a imagem com a dimensão errada.

Estou no iphone 6. retrato.

Isto é o que parece. Observe o fundo branco.

Usando o seguinte código:

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

lrn_launch_screen

Essa não foi a solução que postei, foi:

// 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 maldito! Eu gostaria de ler seu comentário com atenção. Sua solução funciona e é fácil de entender também.

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:

Talvez seja a coisa experimenting . Não tenho certeza de como eu perdi isso. Desculpe, minha culpa.

Obrigado pela ajuda aqui. Vou usar esse código na próxima versão. Parece cobrir todos os casos também. Não precisa de paisagem.

Heh, eu acho que vendi menos do que isso. Eu provavelmente deveria ter dito "isso é o que estamos usando na produção agora e parece funcionar bem" :-)

"isso é o que estamos usando na produção agora" teria nos salvado de cerca de 1 estrela na app store. haha. Sem problemas. Sempre há uma nova versão para salvar o mundo. :)

Fechar este problema btw?

Vou fechar este tíquete, já que ele foi totalmente discutido em detalhes, temos algumas boas soluções.

Só para deixar isso 100% claro para quem está usando um xib LaunchScreen, aqui está o código que fará isso funcionar:

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

Adicionar essas linhas para o application didFinishLaunchingWithOptions método no AppDelegate.m arquivo, logo acima da linha que diz return YES .

@arnemart para ficar mais claro que o método só funcionará para iOS 8+ certo?

Obrigado @arnemart ! Funciona perfeitamente .

Para aqueles que usam LaunchImage , você precisa definir frame e contentMode para que a imagem seja dimensionada corretamente:

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

Assim como o comentário de @arnemart, adicionar essas linhas para o application didFinishLaunchingWithOptions método no AppDelegate.m arquivo, acima da linha que diz return YES .

Esquisito. No RN v.0.11.4, o aplicativo primeiro é iniciado com uma tela preta e, em seguida, LaunchScreen.xib antes de carregar o aplicativo. iOS 9 w / @arnemart de correção https://github.com/facebook/react-native/issues/1402#issuecomment -130236507. Alguma ideia?

@irfaan tente mudar window.backgroundColor para algo como [UIColor redColor], que deve nos dizer se a cor preta está vindo da janela ou outra coisa.

self.window.backgroundColor = [UIColor redColor]; dentro de didFinishLaunchingWithOptions não mudou nada. Ainda preto antes do LaunchScreen.xib. Então, não da janela, parece @nicklockwood

Como você recomenda que eu depure isso?

Parece que o iOS não está carregando seu launchScreen.xib até que o aplicativo seja carregado (nesse ponto, o React o está exibindo como o loadingView).

Talvez seja um erro de configuração no Xcode? Ou possivelmente um bug no iOS 9?

Você já experimentou em um dispositivo ou apenas no simulador?

Obrigado @nicklockwood - Eu estava enfrentando esse problema no dispositivo. Executei no simulador e funcionou perfeitamente, e então deletou + rodou no dispositivo e funcionou bem. Muito estranho. Postarei novamente se o problema surgir novamente.

oi @genexliu , adicionei meu conjunto de imagens "LaunchImage" a Images.xcassets/LaunchImage.launchimage/ mas nem o código que você colou nem meu LaunchScreen.storyboard podem encontrá-los / usá-los (ambos falham silenciosamente). Meu storyboard do LaunchScreen está carregando corretamente quando vejo sua cor de fundo, mas não exibe a imagem referenciada. Alguma ideia?

Além disso, a sequência de inicialização ao executar o XCode parece normal, mas parece haver uma execução adicional da sequência de início / flash branco extra / etc ao executar natal launch da linha cmd.

Acontece que meu problema com o Storyboard não encontrando o LaunchImage era aparentemente um bug com o XCode. Mudei a configuração de inicialização para 'usar catálogo de ativos' e, em seguida, voltei para 'usar storyboard' e começou a funcionar. Não está claro se o código de @genexliu está funcionando para mim ou não, pois loadingViewFadeDelay não parece estar surtindo nenhum efeito.

Este é o meu código:

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

ainda assim, não há atraso entre a exibição do LaunchImage do storyboard e meu React render .

@ "Images / LaunchImage" não parece certo para mim. Provavelmente é apenas @ "LaunchImage"

Oh, oops, sim. Você tem razão. Essa foi uma colagem incorreta - uma das permutações que tentei (mas não a primeira).

Além disso, verifique o código de exemplo em meu comentário acima de 3 meses atrás - há muitos arquivos de imagem de inicialização para diferentes classes de dispositivos.

Doh! Você estava certo. Depois de voltar para LaunchImage ele agora está funcionando. THX!

Alguém pode me indicar alguma documentação sobre isso para o Android?

+1 para Android

cc @dmmiller temos um recurso loadingView no Android?

Olá, estou tendo o mesmo problema e, embora veja que existem algumas soluções postadas aqui, não entendo onde colocar este código. Do meu entendimento, a solução é mudar o código Objective-C, não algo que pode ser feito dentro do próprio React Native, correto? Nesse caso, para onde vai o código postado? No arquivo main.m na raiz do projeto xcode? Obrigado.

@CorpusCallosum o código deve ir no arquivo AppDelegate.m, onde o RCTRootView está configurado.

Obrigado @nicklockwood , vou tentar.

Ei, este código está funcionando para mim agora, na medida em que eu não vejo o flash branco, e minha imagem está sendo carregada na tela inicial, no entanto, agora meu aplicativo real não carrega! Ele apenas permanece na tela de carregamento, embora eu possa ver em meu console, o aplicativo está carregado e em execução, e até mesmo a interação está funcionando (toque e deslize), mas eu não consigo ver meu aplicativo, ele está apenas travado nessa tela inicial. Alguma ideia do porquê?

Este é meu código do meu arquivo 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 Você pode tentar remover a linha
rootView.loadingViewFadeDelay = 1000;
ou ajuste a transição entre a tela inicial e seu aplicativo com seu valor (acho que as unidades são segundos, não milissegundos, é por isso que parece "travado" na abertura).
Se remover a linha completamente não funcionar para você, tente definir valores entre 0-5 (você pode definir valores não inteiros também).

Trabalhando para mim, obrigado pessoal :)

Para aqueles que desejam usar o xib da tela de lançamento como o loadingView, aqui está o código a ser inserido no AppDelegate.m:

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

A última linha é opcional, como mencionei acima, ela define o tempo que o loadingView ficará antes de passar para o próprio aplicativo.

@ david-a, muito obrigado por isso! Tenho lidado com isso desde que comecei a testar o Reagente nativo. 👏

@ david-a, @geriux : Eu também tive que definir launchScreenView.frame = CGRectZero; porque meu LaunchScreen.xib tinha uma imagem de fundo com modo de conteúdo AspectFill e não estava dimensionando corretamente. Cheguei à solução depois de algumas tentativas e erros, não tenho certeza do que causa isso.

@BasitAli sim, desculpe, isso deveria ser melhor documentado. Se você definir o tamanho da visualização como diferente de zero, ela será centralizada na tela. Se você definir como zero, ele será dimensionado para caber na tela.

@ david-a, muito obrigado! Seu comentário deve ser incluído no boilerplate ou, pelo menos, fazer parte da documentação principal do react nativo. Não sei por que esse problema foi encerrado em março de 2015, ele claramente ainda existe no RN 0,20 em fevereiro de 2016.

Seria bom se alguém pudesse fazer o PR para o documento.

Os conselhos da vossa galera me ajudam muito (no IOS, funcionando perfeitamente), alguém acha um jeito de consertar isso no Android?

@weiyisheng , estou usando o react-native-splashscreen sugerido por @braco no Android junto com a correção discutida acima no iOS.

@braco @BasitAli SIM, ajudou, vou usar no meu App, é uma boa ideia. Obrigado pessoal.

@BasitAli por que não usá-lo no iOS por curiosidade?

Meu aplicativo é animado perfeitamente da tela inicial para a tela de login (o logotipo se move para cima e os campos de login saltam). O plugin rn-splashscreen desaparece, o que não combina muito bem com a minha animação. Tive de usá-lo no Android, pois não tinha outra escolha.

@BasitAli , parece que o plug-in react-native-splashscreen obedece à configuração rootView.loadingViewFadeDuration , desde que você defina depois de anexá-lo, então isso deve desativar o fade:

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

Existe alguma maneira de remover aquela pequena mensagem no topo dizendo "Carregando do arquivo pré-agrupado"?

@rclai definir esquema para liberação

Ah! Obrigado!

Existe alguma solução reagente nativa para a tela inicial de ambas as plataformas? Digitar em arquivos internos de ambas as plataformas torna o uso do react-native inútil. Resposta simples, por favor. Obrigado

@rclai

Existe alguma maneira de remover aquela pequena mensagem no topo dizendo "Carregando do arquivo pré-agrupado"?

Isso não é mostrado no modo de liberação, apenas no modo de depuração. Se você quiser ocultá-lo no modo de depuração também, poderá ocultá-lo colocando [RCTDevLoadingView setEnabled:NO]; em seu AppDelegate.

@nicklockwood Olá, correto? Se não, o que devo alterar / excluir?

  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 parece certo para mim. Se você ainda estiver vendo um flash na inicialização, tente configurar

rootView.loadingViewFadeDelay

Para um valor maior (em segundos - o padrão é 0,25)

EDITAR:

Está linha

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

Provavelmente deveria ser apenas

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

Obrigado, em qual pasta devo adicionar essas imagens? Preciso de Contents.json extra para isso ou não? Eu tenho vários erros nesse código, começando com
(https://cloud.githubusercontent.com/assets/10398337/13778676/e01e3d32-eabf-11e5-95bf-d7a1205a5ca1.png)
Olhar fixamente para:

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

@TeodorKolev Xcode tem uma GUI para adicioná-los. Clique em Images.xcassets, clique no botão + e selecione "App Icons & Launch Images"> "New iOS Launch Image".

screen shot 2016-03-15 at 13 47 48

@TeodorKolev para corrigir os erros, você precisa adicionar

#import "RCTUtils.h"

Em seu AppDelegate.

Muito obrigado, mas eu quero ver a tela inicial até que meu URL do WebView carregue totalmente, e agora ele não está mais funcionando assim. Respeito!

@nicklockwood. Você tem algum remédio para este?

Qual é o método atual para corrigir isso? Já que se passou um ano e alguns meses desde que o problema apareceu, duvido que ele seja realmente resolvido, então estou me perguntando qual é o remédio atual. Qual arquivo precisa ser alterado e qual código precisa ser modificado?

Editar: estou apenas usando uma tela preta com o launchscreen.xib, mas na metade ela fica branca antes que o aplicativo carregue por completo.

@ hasen6 o problema já foi corrigido, mas há algum trabalho necessário por parte do desenvolvedor.

Conforme discutido nos comentários acima, você precisa definir rootView.loadingView com algum conteúdo a ser mostrado no lugar da tela branca e ajustar rootView.loadingViewFadeDelay para garantir que a visualização de carregamento não fique oculta antes de seu o aplicativo terminou de carregar.

Se você deseja apenas mostrar uma tela preta, pode não precisar se preocupar com um loadingView e apenas definir rootView.backgroundColor como preto, mas você terá que experimentar.

Eu mudei rootView.backgroundColor = [UIColor clearColor]; para rootView.backgroundColor = [UIColor blackColor]; but it didn't make any difference. Doing a search in XCode for rootView.loadingView` não retornou nenhum resultado.

@ hasen6 você precisa descobrir de onde vem a cor branca - pode ser que haja uma visualização dentro do seu aplicativo JS que é branca e é mostrada por um tempo antes de o conteúdo carregar.

loadingView é uma propriedade de RCTRootView , da qual você presumivelmente tem uma instância dentro de seu AppDelegate. O código real rootView.loadingView não aparecerá em seu Xcode a menos que você mesmo o tenha adicionado. Aqui está um exemplo de como você pode usá-lo:

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

Meu aplicativo não é branco em lugar nenhum. Todos os meus aplicativos mostram a mesma tela branca ao carregar depois que a tela de inicialização é exibida, então tenho certeza de que não é um problema com meus aplicativos.

Portanto, preciso adicionar esse código ao appdelegate.m? Isso também não funcionou. Acho que deve ser quase impossível consertar, caso contrário não teria se passado um ano sem que os desenvolvedores ainda não tivessem resolvido. Considerando o quão ruim faz os aplicativos parecerem, obviamente também estaria no topo da lista de solução.

FWIW, é assim que estou resolvendo esse problema. Estou usando a solução LaunchScreen.xib e David-a:

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

Este código é inserido logo abaixo

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

Se eu substituir esse código pelo código de amostra de Nicklockwood, o flash branco retorna.

Uau! Ok, esse funciona. Obrigado grittathh!

@grittathh @ hasen6 ah, OK. Não me lembrei de que o loadingView era dimensionado automaticamente para caber na tela se tivesse tamanho zero, mas aparentemente esse nunca foi o caso ¯_ (ツ) _ / ¯.

@ hasen6 aqui está uma versão modificada do código que deve funcionar (a solução xib também é adequada, mas redundante se você estiver usando apenas uma tela preta).

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

Nota: 1 é um valor bastante grande para loadingViewFadeDelay, pois significa que os usuários têm que esperar um segundo a mais antes de o aplicativo iniciar. Eu sugiro configurá-lo com o valor mais baixo possível (0,25 é o padrão, o que é bom para a maioria dos aplicativos).

Sim, descobri que 1 era um pouco longo e estava faltando a animação de abertura em um dos meus aplicativos. Eu descobri que até 0,1 está bom. Obrigado pela ajuda.

Eu concordo com @ hasen6 . Certamente parece um pouco estranho que os usuários tenham que mergulhar imediatamente em Objective-C ( AppDelegate.m ) e ajustar algum código imediatamente ao gerar um aplicativo React Native. Não seria possível para o React Native gerar código com essa correção já incorporada? Ou para apresentar uma solução mais abstrata para a configuração da tela inicial do JavaScript (ou uma linguagem de configuração declarativa)?

@johanatan Ironicamente, os dois maiores e mais duradouros problemas do React Native têm a ver com algum tipo de flash branco. Este erro e o flash branco nas imagens.

Quando eu uso meu LaunchScreen xib ele tende a ser maior, alguma solução?

O que tende a ser maior?

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

a visualização da IU de carregamento, não parece redimensionar, é suposto ser o mesmo que minha tela inicial, que é meu LaunchScreen.xib

Estou usando classes de tamanho e restrições BTW

@akoshdee correto - você precisará definir o tamanho da visualização explicitamente para corresponder ao tamanho da tela. Usando

loading.frame = [UIScreen mainScreen].bounds;

já mudei o frame mas ainda não funciona

qualquer solução para android?

@ajoshdee A loadingView.frame = [UIScreen mainScreen].bounds; não funcionou para mim, mas funcionou: loadingView.frame = self.window.bounds;

Isso é o que estou usando:

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

Olá! Eu defino a cor para reagir à vista:
rootViewController.view.backgroundColor = [UIColor blackColor];

@ py110 @ajwhite

A solução Android é estupidamente simples a ponto de ficar irritado comigo mesmo por quanto tempo levei para descobri-lo.

Envolve uma tela inicial de 3 estágios.

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

Eu tive uma implementação semelhante @mehcode - eu gosto do que você tem aqui. Estou procurando uma maneira de acessar o gerenciador de instâncias RN, mas não vi que havia uma chamada de getReactNativeHost() , muito bom saber.

Eu tinha feito o seguinte, (não feliz com isso)

  1. SplashActivity iniciado quando o aplicativo abre
  2. Abre imediatamente o MainActivity e finish()
  3. MainActivity inicia SplashActivity com uma bandeira indicando que está em "modo de primeiro plano" assim que começa a mostrar o respingo acima de MainActivity . Após um curto período de tempo, o SplashActivity fecha-se revelando o aplicativo.

@ajwhite

Obrigado. O efeito é muito suave.

Em meus projetos atuais, literalmente copiei ReactActivity em minha base de código e tornei mReactInstanceMangager protegido em vez de privado.

No react-native 0,29 (deveria ter dito no comentário), a equipe react nativa nos deu um método público getReactNativeHost() para entrar nele.

Esse contêiner ReactNativeHost é uma jogada brilhante. Este é exatamente o problema que encontrei - não ser capaz de conectar-se ao ciclo de vida da MainActivity.

Ref para os interessados: https://github.com/facebook/react-native/commit/49f20f41546e3ba8e7fe43c84c4c701684d0434d#diff -1346852de0c7f8466a36d42de50ec808R20

Para adicionar a isso ...

Uma solução que encontrei foi atribuir a rootView uma cor de fundo, mas usar [UIColor colorWithPatternImage:img] .

Isso não requer atrasos para garantir que ele permaneça visível até que esteja totalmente carregado.

Um snippet completo (e usando a dica fornecida por @ dvine-multimedia) que encontrará o LaunchImage desejado para o dispositivo está abaixo:

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

O LaunchImage agora permanece visível até que o pacote reagente nativo seja totalmente carregado.

Eu tentei quase todos os blocos de código nesta conversa sem chance, mas este funcionou perfeitamente.
Obrigado @ dbonner1987 !

alguma solução para android?

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


@sercanov @ dbonner1987 Também usa a abordagem mencionada acima para que o iOS faça a tela de inicialização do javascript.

@arnemart Obrigado, meio que ainda funciona em RN 0.30.0. Tive que deletar meu aplicativo e reinstalá-lo. Teve o flash branco da primeira vez, mas nenhum depois disso.

@nicklockwood Existe algum tipo de retorno de chamada que posso usar para saber quando o javascript real é carregado. A razão para isso é que, quando meu aplicativo está navegando entre as páginas, há alguma transparência onde rootView.backgroundColor é visível no plano de fundo da visualização. Também recebo um problema semelhante com o plugin Drawer que estou usando durante a transição de abertura da gaveta.
Então, eu gostaria de fazer algo como:

  • Defina a cor de fundo do rootView para a imagem do iniciador, usando a abordagem de @ dbonner1987 acima durante o processo de carregamento.
  • Quando o javascript termina de carregar e a primeira rota de navegação começa (ou algo parecido)
  • Defina a cor de fundo de rootView novamente para branco.

Então, basicamente, preciso de um retorno de chamada para saber quando o carregamento estiver concluído.

@ UKDeveloper99 Por favor, consulte a documentação que

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

@mehcode isso é perfeito, obrigado !!

Alguém tem sugestões sobre como implementar um LaunchScreen.storyboard que desliga assim que o pacote é carregado? Atualmente, ele é exibido por um determinado período de tempo, então vejo a tela branca e o aplicativo carrega RN 34.1 xcode 8

@ajoshdee Eu tive problemas semelhantes onde a visão acabou sendo muito maior do que a tela. Não tenho certeza se está relacionado, mas estava usando o AutoLayout no meu LaunchScreen.xib .

Eu precisava definir também

launchScreenView.autoresizingMask = UIViewAutoresizingNone;

Para obter o tamanho adequado.

Portanto, https://github.com/facebook/react-native/issues/1402#issuecomment -166963438 com essa linha adicionada acima

Você também pode atualizar a cor de inicialização em substituir esta linha em appdelegate.m:

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

por esta linha:
rootView.backgroundColor = [[UIColor alloc] initWithRed:0.94 green:0.90 blue:0.89 alpha:1.0];

e encontre a cor que deseja com este site

Alguém conseguiu resolver isso no Android?

Aqui está uma solução para iOS e Android: https://github.com/mehcode/rn-splash-screen .
Ocultei a tela inicial na função de renderização do meu app.tsx (o ponto de entrada) e mostrei a mesma imagem até que todas as minhas solicitações https fossem concluídas.

Meu código:
`` `
public render ()
{
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 alguma solução para isso se eu estiver usando o storyboard para a tela inicial? Eu não tenho mais minhas imagens da tela de lançamento para cada dimensão.

In react nativo para iOS dentro de AppDelegate.m altere a seguinte linha escrevendo seus códigos de cores RGB de acordo:

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

Para VERMELHO, mude o número 52
Para VERDE mude o número 73
Para AZUL mude o número 94

_Observação: Estou usando o react nativo v0.51.0_

Ainda não há solução para o Android?

@otoinsa veja a resposta acima https://github.com/facebook/react-native/issues/1402#issuecomment -339336380 por @neomib. Existem algumas outras bibliotecas de tela inicial que funcionam tão bem, por exemplo, https://github.com/crazycodeboy/react-native-splash-screen.

Alguma sugestão sobre o storyboard usado como LaunchScreen?

Minha abordagem foi assim (mas o aplicativo trava na inicialização)

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

o aplicativo trava com o seguinte erro:

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 -

Obrigado.

substituído

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

com

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

agora o aplicativo é iniciado, mas obtenho um fundo preto.

Ou você pode usar https://github.com/crazycodeboy/react-native-splash-screen é muito mais fácil :)

Esta página foi útil?
0 / 5 - 0 avaliações