A barra de status e a barra de navegação aparecem acima dos limites da minha visualização no iOS 7

435

Recentemente, baixei o Xcode 5 DP para testar meus aplicativos no iOS 7. A primeira coisa que notei e confirmei é que os limites da minha visualização nem sempre são redimensionados para dar conta da barra de status e da barra de navegação.

Em viewDidLayoutSubviews, imprimo os limites da exibição:

{{0, 0}, {320, 568}}

Isso resulta no meu conteúdo aparecendo abaixo da barra de navegação e da barra de status.

Eu sei que eu poderia explicar a altura obtendo a altura da tela principal, subtraindo a altura da barra de status e a altura da barra de navegação, mas isso parece um trabalho extra desnecessário.

Como posso corrigir esse problema?

Atualizar:

Encontrei uma solução para esse problema específico. Defina a propriedade translúcida da barra de navegação como NO:

self.navigationController.navigationBar.translucent = NO;

Isso evitará que a exibição seja enquadrada embaixo da barra de navegação e da barra de status.

No entanto, não encontrei uma correção para o caso quando você deseja que a barra de navegação seja translúcida. Por exemplo, ao visualizar uma foto em tela cheia, desejo que a barra de navegação seja translúcida e a vista seja enquadrada embaixo dela. Isso funciona, mas quando alterno a exibição / ocultação da barra de navegação, experimentei resultados ainda mais estranhos. A primeira subvisão (um UIScrollView) obtém seus limites e a origem é alterada toda vez.

beebcon
fonte
Eu também estou recebendo o mesmo problema no Xcode 5 DP
Gopesh Gupta
Deixe-me saber se você vai ter alguma solução
Gopesh Gupta
1
Procure na barra de navegação uma propriedade de cor da tonalidade. Você poderá alterar essa cor azul para o que quiser.
precisa saber é
9
Às vezes, odeio atualizar o iOS porque a Apple nunca lhe deu a oportunidade de manter seu aplicativo compatível com versões anteriores.
Bagusflyer
3
Se o problema estiver relacionado à exibição abaixo da barra de status após ocultar a barra superior do controlador de navegação, consulte a resposta por @Stunner stackoverflow.com/a/18976660/235206 como a solução
MiKL

Respostas:

495

Você pode conseguir isso implementando uma nova propriedade chamada edgesForExtendedLayoutno iOS7 SDK. Adicione o seguinte código para conseguir isso,

if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
        self.edgesForExtendedLayout = UIRectEdgeNone;

Você precisa adicionar o acima em seu -(void)viewDidLoadmétodo.

O iOS 7 traz várias alterações na forma como você layout e personaliza a aparência da sua interface do usuário . As alterações no layout do controlador de exibição, cor da tonalidade e fonte afetam todos os objetos do UIKit no seu aplicativo. Além disso, os aprimoramentos nas APIs de reconhecimento de gestos oferecem controle mais refinado sobre as interações de gestos.

Usando os controladores de exibição

No iOS 7, os controladores de exibição usam o layout de tela cheia. Ao mesmo tempo, o iOS 7 oferece um controle mais granular sobre a maneira como um controlador de visualização apresenta suas visualizações. Em particular, o conceito de layout de tela cheia foi refinado para permitir que um controlador de visualização especifique o layout de cada extremidade da visualização.

A wantsFullScreenLayoutpropriedade do controlador de exibição está obsoleta no iOS 7. Se você especificar atualmente wantsFullScreenLayout = NO, o controlador de exibição poderá exibir seu conteúdo em um local inesperado da tela quando executado no iOS 7.

Para ajustar como um controlador de exibição expõe suas exibições, UIViewController fornece as seguintes propriedades:

  • edgeForExtendedLayout

A edgesForExtendedLayoutpropriedade usa o UIRectEdgetipo, que especifica cada uma das quatro arestas de um retângulo, além de especificar nenhuma e todas. Use edgesForExtendedLayoutpara especificar quais arestas de uma vista devem ser estendidas, independentemente da translucidez da barra. Por padrão, o valor dessa propriedade é UIRectEdgeAll.

  • extendedLayoutIncludesOpaqueBars

Se o seu design usa barras opacas, refine edgesForExtendedLayouttambém definindo a extendedLayoutIncludesOpaqueBarspropriedade como NO . (O valor padrão de extendedLayoutIncludesOpaqueBarsé NO .)

  • automaticAdjustsScrollViewInsets

Se você não deseja que as inserções de conteúdo de uma exibição de rolagem sejam ajustadas automaticamente, defina automaticallyAdjustsScrollViewInsetscomo NÃO . (O valor padrão de automaticallyAdjustsScrollViewInsetsé YES .)

  • topLayoutGuide, bottomLayoutGuide

As propriedades topLayoutGuidee bottomLayoutGuideindicam a localização das arestas da barra superior ou inferior na exibição de um controlador de exibição. Se as barras se sobrepuserem à parte superior ou inferior de uma vista, você poderá usar o Interface Builder para posicionar a vista em relação à barra, criando restrições na parte inferior topLayoutGuideou na parte superior do bottomLayoutGuide. (Se nenhuma barra deve se sobrepor à vista, a parte inferior topLayoutGuideé igual à parte superior da vista e a parte superior bottomLayoutGuideé igual à parte inferior da vista.) Ambas as propriedades são criadas preguiçosamente quando solicitadas.

Consulte, doc da apple

Nandha
fonte
2
Não será compilado no iOS6. Eu acho que deveria ser escrita como performSelector ...
Shmidt
8
Sim, é por isso que incluí a seleção do seletor com a condição if, if ([self respondesToSelector: @selector (edgeForExtendedLayout)]))
Nandha
19
Isso não funcionaria se eu não tivesse barra de navegação. Nesse caso, meu vista é estende-se por trás da barra de estado ..
Van Du Tran
4
Eu tenho o mesmo problema que @VanDuTran. edgeForExtendedLayout não ajuda se a barra de navegação estiver oculta.
fishinear perto de 24/09/13
6
ele funciona, mas ... não há mais efeito translúcido ... como podemos preservar efeito translúcido bem ...
Dipu Rajak
110

Você não precisa calcular até que ponto mudar tudo, há uma construção na propriedade para isso. No Construtor de interface, realce seu controlador de exibição e navegue até o inspetor de atributos. Aqui você verá algumas caixas de seleção ao lado das palavras "Estender arestas". Como você pode ver, na primeira captura de tela, a seleção padrão é para o conteúdo aparecer sob as barras superior e inferior, mas não sob as barras opacas, e é por isso que definir o estilo da barra como não translúcido funcionou para você.

Como você pode ver na primeira captura de tela, existem dois elementos da interface do usuário ocultos abaixo da barra de navegação. (Ativei os wireframes no IB para ilustrar isso) Esses elementos, um UIButton e um UISegmentedControl, têm sua origem "y" definida como zero, e o controlador de exibição está definido para permitir conteúdo abaixo da barra superior.

insira a descrição da imagem aqui

Esta segunda captura de tela mostra o que acontece quando você desmarca a caixa de seleção "Abaixo das barras superiores". Como você pode ver, a exibição dos controladores de exibição foi deslocada adequadamente para que sua origem y estivesse logo abaixo da barra de navegação.

insira a descrição da imagem aqui

Isso também pode ser realizado através de programação através do uso de -[UIViewController edgesForExtendedLayout]. Aqui está um link para a referência de classe para edgeForExtendedLayout e para UIRectEdge

[self setEdgesForExtendedLayout:UIRectEdgeNone];
Mick MacCallum
fonte
15
Como faço o mesmo para apenas exibir em um .xib?
bobics
2
Eu adicionei uma etiqueta em vista e eu segui sua instrução, mas isso não está funcionando para mim
RMRAHUL
5
@bobics A resposta para a pergunta XIB é: "Você não pode". Não através do IB de qualquer maneira. Arquive um radar e espere que a Apple resolva o problema.
memmons
Obrigado @ 0x7fffffff, Esta foi apenas a informação que eu estava procurando e foi muito útil.
campo
33

Criei minha visão programaticamente e isso acabou funcionando para mim:

- (void) viewDidLayoutSubviews {
    // only works for iOS 7+
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;

        // snaps the view under the status bar (iOS 6 style)
        viewBounds.origin.y = topBarOffset * -1;

        // shrink the bounds of your view to compensate for the offset
        viewBounds.size.height = viewBounds.size.height + (topBarOffset * -1);
        self.view.bounds = viewBounds;
    }
}

Origem (na seção topLayoutGuide na parte inferior da página 39).

Stunner
fonte
Finalmente encontrei uma resposta que realmente funciona para isso. Bom trabalho!
StuartM
1
Para resolver o problema pelo qual a exibição do controlador de exibição aparece sob a barra de status quando a barra de navegação está oculta, esse é o código que captura a exibição na barra de status.
mikl
Nota: isso empurrará a parte inferior da sua visualização para fora da tela.
memmons
1
Além disso, a menos que você esteja construindo apenas para iOS7, o código acima gerará um erro - topLayoutGuideé apenas iOS7.
memmons
1
Observe também que quando sua visualização principal é um UITableView, os viewDidLayoutSubviews serão chamados em cada rolagem. Seu UITableView será reduzido até a altura ter 15 px. Adicione um sinalizador para executar esse código apenas uma vez. ;)
Thomas Johannesmeyer
30

Solução Swift 3 / Swift 4 que também funciona com arquivos NIBs / XIB no iOS 10+:

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}
flo_23
fonte
Isso é o que me ajudou ... Tão simples. Obrigado :-)
Hernan Arber 15/17
Obrigado é realmente útil
Muhammad Ahmed Baig
Esta é a melhor solução para 10.x Swift 3+ IMO
shokaveli
10

Se você deseja que a exibição tenha a barra de navegação translúcida (o que é bastante legal), é necessário configurar um contentInset ou semelhante.

Aqui está como eu faço isso:

// Check if we are running on ios7
if([[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."][0] intValue] >= 7) {
      CGRect statusBarViewRect = [[UIApplication sharedApplication] statusBarFrame];
      float heightPadding = statusBarViewRect.size.height+self.navigationController.navigationBar.frame.size.height;

      myContentView.contentInset = UIEdgeInsetsMake(heightPadding, 0.0, 0.0, 0.0);
}
Magnus
fonte
3
por que você não pode compará-lo diretamente com o 7.0 #
Leena
1
lol eu entendi: a verificação contra uma versão específica com menor adição é menos robusta. Mas você está verificando se o valor for maior ou igual a tão em comparação com 7,0 faria muito bem aqui;)
EeKay
1
@leena - Este é um recurso do 7.xe versões posteriores - por isso, verifico se a versão é 7 ou superior e pulo as pequenas revisões na verificação.
Magnus
2
Eu tive um problema com o meu tableView sendo exibido atrás da minha barra de guias. O que fez a última linha da minha tabela nunca rolar acima da barra de guias. Eu fixo-lo assim: myTableView.contentInset = UIEdgeInsetsMake (0, 0,0, TabbarHeight, 0)
James Laurenstin
contentInseté uma propriedade de UIScrollView. E se minha visão principal não for uma subclasse de UIScrollView. Então, como eu solucionaria o problema de sobreposição?
Pwner
9

edgesForExtendedLayoutfaz o truque para o iOS 7. No entanto, se você criar o aplicativo no iOS 7 SDK e implantá-lo no iOS 6, a barra de navegação aparecerá translúcida e as visualizações ficarão abaixo. Portanto, para corrigi-lo no iOS 7 e no iOS 6, faça o seguinte:

self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
    self.edgesForExtendedLayout = UIRectEdgeNone;   // iOS 7 specific
Raj Pawan Gumdal
fonte
9

No arquivo plist dos aplicativos, adicione uma linha, chame-a de "Exibir aparência da barra de status com base no controlador" e defina-a como NÃO .

Idan
fonte
7

O truque mais simples é abrir o arquivo NIB e executar estas duas etapas simples:

  1. Apenas alterne isso e defina-o como você preferir:

Digite a descrição da imagem aqui

  1. Selecione aqueles / UIIMageView's / ... que você deseja mover para baixo. No meu caso, apenas o logotipo foi sobreposto e eu configurei o delta para +15; (OU -15, se você escolheu o iOS 7 na etapa 1)

Digite a descrição da imagem aqui

E o resultado :

Antes Depois de

Riskov
fonte
6
Funciona, mas parece uma solução difícil de manter. Seria melhor apenas corrigir o problema em vez de corrigi-lo.
NLemay
seria melhor fazê-lo por meio de programação para subviews tudo de vista, porque ele não funciona se for aplicada a vista principal
wildmonkey
5

Solução rápida:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.edgesForExtendedLayout = UIRectEdge.None
}
fatihyildizhan
fonte
4
Agora é edgeForExtendedLayout = [] #
Leon Leon
1
Como esta é uma resposta pública, não devemos esquecer de ligar para:super.viewWillAppear(animated)
prodos
4

Gostaria de expandir a resposta de Stunner e adicionar uma ifdeclaração para verificar se é o iOS-7, porque quando o testei no iOS 6, meu aplicativo falharia.

A adição seria adicionar:

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)

Então, eu sugiro adicionar este método ao seu MyViewControler.marquivo:

- (void) viewDidLayoutSubviews {
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;
        viewBounds.origin.y = topBarOffset * -1;
        self.view.bounds = viewBounds;
    }
}
werdsackjon
fonte
4

Swift 3

override func viewWillAppear(_ animated: Bool) {
    self.edgesForExtendedLayout = []
}
Shahrukh
fonte
3

Eu tenho um cenário em que uso o BannerViewController escrito pela Apple para exibir meus anúncios e um ScrollViewController incorporado no BannerViewController.

Para impedir que a barra de navegação oculte meu conteúdo, tive que fazer duas alterações.

1) Modifique BannerViewController.m

- (void)viewDidLoad
{
   [super viewDidLoad];
   float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
   if (systemVersion >= 7.0) {
      self.edgesForExtendedLayout = UIRectEdgeNone;
   }
}

2) Modifique meu ScrollViewContoller

- (void)viewDidLoad
{
    [super viewDidLoad];
    float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (systemVersion >= 7.0) {
        self.edgesForExtendedLayout = UIRectEdgeBottom;
    }
}

Agora, os anúncios são exibidos corretamente na parte inferior da visualização, em vez de serem cobertos pela barra de navegação e o conteúdo na parte superior não é cortado.

Xavier John
fonte
2

basta definir o seguinte código em exibição aparecerá.

  if ([[[UIDevice currentDevice] systemVersion] floatValue]<= 7) {
self.edgesForExtendedLayout = UIRectEdgeNone;
 }
Amit Shelgaonkar
fonte
Esta é a única coisa que funcionou na minha circunstância.
goobliata 12/03
2

faça restrições ao layout superior como este insira a descrição da imagem aqui

carmen_munich
fonte
2

Swift 4.2 - Xcode 10.0 - iOS 12.0:

if #available(iOS 11.0, *) {} else {
  self.edgesForExtendedLayout = []
  self.navigationController?.view.backgroundColor = .white
}
juliancadi
fonte
1

Para mim, a solução mais simples é adicionar duas chaves ao plist

insira a descrição da imagem aqui

Giuseppe
fonte
+1, eu tinha a "Barra de status inicialmente oculta" = SIM, mas ao adicionar "Visualizar a aparência da barra de status com base no controlador" = NÃO, me livrei da barra de status.
Jonas Byström 28/10
1

Adicione a chave "Exibir aparência da barra de status baseada em controlador" na lista suspensa como uma linha em info.plist. Algo assim:

Digite a descrição da imagem aqui

Kursat Turkay
fonte
interesting.it ajudou nos meus projetos cocos2d. Ao alternar essa opção, posso ver que a barra de status superior foi completamente desaparecida ou exibida.
Kursat Turkay 19/10/2013
1

Eu tive o mesmo problema com meu aplicativo por iPads (armv7, armv7s, amr64) apenas apresentando outro UIViewController e depois descartá-los na barra de status sob a barra de status ... passo muito tempo para encontrar qualquer solução para isso. Eu estou usando o storyboard e no InterfaceBuilder for UIViewController, o que torna terrível eu definir a Apresentação em tela cheia -> Contexto atual e corrigir esse problema. Funciona no meu aplicativo apenas para iPads => iOS8.0 (testando com iOS8.1) e para iPads com iOS 7.1 não funciona !!veja a captura de tela

Alexej W.
fonte
No meu caso, minha visualização principal estava sobreposta à minha tabBar e eu não sabia o porquê. Acontece que a opção Estender bordas> Abaixo das barras inferiores foi marcada. Foi realmente difícil perceber isso porque o plano de fundo do meu aplicativo era branco e só gerava alguma opacidade no meu tabBar. Obrigado!
Jesus Rodriguez
0

Etapas para ocultar a barra de status no iOS 7:

1. Vá para o arquivo info.plist do aplicativo.

2.E definir, exibir a aparência da barra de status baseada em controlador: Booleano NÃO

Espero ter resolvido o problema da barra de status .....

Chandrika
fonte
0

No meu caso, tendo loadView () interrompido
este código: self.edgesForExtendedLayout = UIRectEdgeNone

mas depois de excluir o loadView () tudo funcionou bem

DevB2F
fonte