Explicando a diferença entre automaticamenteAdjustsScrollViewInsets, extendedLayoutIncludesOpaqueBars, edgeForExtendedLayout no iOS7

250

Eu tenho lido muito sobre a transição da interface do iOS7.

Eu não sou capaz de conseguir o que essas três propriedades automaticallyAdjustsScrollViewInsets, extendedLayoutIncludesOpaqueBars, edgesForExtendedLayout??

Por exemplo, estou tentando fazer com que meus controladores de exibição iniciem abaixo da barra de status, mas não consigo alcançá-lo.

user1010819
fonte
5
e por que você acha que eu não li isso .. O problema é que não está funcionando como esperado como em eu não ter entendido bem !! .. isso é a razão?
user1010819
1
Ohhh, eu entendi errado o que você estava dizendo lá. Eu não estava tentando parecer condescendente, é que quando algumas pessoas fazem perguntas como essa e são novas no site, elas perdem as soluções óbvias.
Erdekhayser 15/09/13
8
No método viewDidLoad, adicione if ([self respondesToSelector: @selector (edgeForExtendedLayout)]) self.edgesForExtendedLayout = UIRectEdgeNone; o que forçará sua exibição a começar abaixo da barra de status.
Nandha

Respostas:

629

A partir do iOS7, os controladores de exibição usam o layout de tela cheia por padrão. Ao mesmo tempo, você tem mais controle sobre como ele expõe suas visualizações, e isso é feito com essas propriedades:

edgeForExtendedLayout

Basicamente, com essa propriedade, você define quais lados da visualização podem ser estendidos para cobrir a tela inteira. Imagine que você insere um UIViewControllerem um UINavigationController. Quando a exibição desse controlador de exibição é organizada, ela começa onde a barra de navegação termina, mas essa propriedade define quais lados da exibição (superior, esquerda, inferior, direita) podem ser estendidos para preencher a tela inteira.

Vamos vê-lo com um exemplo:

UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [UIColor redColor];
UINavigationController *mainNavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];

Aqui você não está definindo o valor de edgesForExtendedLayout, portanto, o valor padrão é obtido ( UIRectEdgeAll), portanto a exibição estende seu layout para preencher a tela inteira.

Este é o resultado:

sem arestas para um layout estendido, a exibição preenche toda a tela

Como você pode ver, o fundo vermelho se estende atrás da barra de navegação e da barra de status.

Agora, você definirá esse valor como UIRectEdgeNone, dizendo ao controlador de exibição para não estender a exibição para cobrir a tela:

UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [UIColor redColor];
viewController.edgesForExtendedLayout = UIRectEdgeNone;
UINavigationController *mainNavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];

E o resultado:

com edgeForExtendedLayout definido, a visualização fica logo abaixo da barra de navegação


automaticAdjustsScrollViewInsets

Essa propriedade é usada quando sua visualização é UIScrollViewou semelhante, como a UITableView. Você deseja que sua tabela comece onde a barra de navegação termina, porque você não verá todo o conteúdo, se não, mas ao mesmo tempo deseja que sua tabela cubra a tela inteira ao rolar. Nesse caso, definir edgesForExtendedLayoutcomo Nenhum não funcionará porque sua tabela começará a rolar onde a barra de navegação termina e ela não ficará atrás dela.

Aqui é onde essa propriedade é útil, se você permitir que o controlador de visualização ajuste automaticamente as inserções (configurando essa propriedade como YES, também o valor padrão), ele adicionará inserções na parte superior da tabela, para que a tabela comece onde a navegação a barra termina, mas a rolagem cobre a tela inteira.

É quando está definido como NÃO:

a tabela irá rolar por toda a tela, mas começa parcialmente coberta

E SIM (por padrão):

a tabela rola sobre a tela inteira e começa logo abaixo da navegação

Nos dois casos, a tabela rola atrás da barra de navegação, mas no segundo caso (YES), ela começará abaixo da barra de navegação.


extendedLayoutIncludesOpaqueBars

Este valor é apenas uma adição aos anteriores. Por padrão, este parâmetro está definido como NÃO. Se a barra de status for opaca, as visualizações não serão estendidas para incluir a barra de status, mesmo se você estender sua visualização para cobri-la ( edgesForExtendedLayoutpara UIRectEdgeAll).

Se você definir o valor como YES, isso permitirá que a exibição volte novamente para a barra de status.

Se algo não estiver claro, escreva um comentário e eu responderei.

Como o iOS sabe qual UIScrollView usar?

O iOS obtém a primeira subvisão na visualização do seu ViewController, aquela no índice 0 e, se for uma subclasse UIScrollView, aplica as propriedades explicadas a ela.

Obviamente, isso significa que UITableViewControllerfunciona por padrão (já que UITableViewé a primeira visualização).

Antonio MG
fonte
Precisamos definir essas propriedades apenas se estivermos mostrando a barra de navegação padrão e não a barra de navegação personalizada, certo?
Hemang
1
Não, se você usar a barra de navegação do iOS, mas com seu próprio design, precisará usar as mesmas propriedades. Se você simplesmente criar sua barra de navegação, essas propriedades não funcionarão.
Antonio MG
Não entendo por que surge uma pequena camada enegrecida em toda a exibição? Por favor ajude? : /
aZtraL-EnForceR
24
Esta explicação é muito melhor que o iOS 7 UI Transition Guide. Isso deveria substituir o guia, o que não fazia sentido para mim.
25414 Sam
2
Eu acho que extendedLayoutIncludesOpaqueBars deve ser YES por padrão em vez de NO. A alteração das cores da visualização (translucidez) não deve afetar o layout.
Vladimír Slavík
15

Não tenho certeza se você está usando storyboards, mas se estiver, para fazer com que seus controladores de exibição sejam iniciados abaixo da barra de status (e acima da barra inferior):

Selecione o controlador de exibição em IB. No inspetor de atributos, desmarque 'Estender arestas - sob as barras superiores' e 'Estender arestas - sob barras inferiores'.

Ali Beadle
fonte
ESTÁ BEM. Então acho que o que Nandha sugeriu acima alcançará o mesmo resultado programaticamente. Se não funcionar em viewDidLoad, talvez seja necessário movê-lo para viewDidLayoutSubviews.
Ali Beadle
Indica se o layout estendido inclui ou não barras opacas. @property (nonatomic, assign) BOOL extendedLayoutIncludesOpaqueBars Discussão O valor padrão é NO.
Abdul Yasin
+1, você me deu uma dica para fazer check-in no Storyboard. E resolvi minha metade do meu problema.
Selva
10

Estou usando storyboards e, usando os conselhos acima, funcionou, mas não sabia exatamente como implementá-lo. Abaixo está um breve exemplo de como ele resolveu o problema, colocando a solução recomendada no ViewController.

import Foundation
import UIKit

// This ViewController is connected to a view on a storyboard that 
// has a scrolling sub view.
class TheViewController: UIViewController {

  // Prepares the view prior to loading.  Putting it in viewDidAppear didn't work.
  override func viewWillAppear(animated: Bool) {

    // this method is an extension of the UIViewController 
    // so using self works as you might expect.
    self.automaticallyAdjustsScrollViewInsets = false

    // Default is "true" so this sets it to false tells it to use 
    // the storyboard as you have it placed
    // and not how it thinks it should place it.
  }

}

Meu problema: Ajuste automático definido como verdadeiro por padrão, causando uma diferença entre o design do storyboard e o simulador Ajuste automático definido como verdadeiro por padrão, causando uma diferença entre o design do storyboard e o simulador

Resolvido: código acima aplicado, desativando o ajuste automático. Código acima aplicado, desativando o ajuste automático.

Christopher Wade Cantley
fonte
5
se você ativar o AutomaticAdjustsScrollViewInsets como YES, defina a restrição superior como superview, não o topGuideLayout.
Xmkevinchen
5

Resolvi esse problema adicionando esta linha, mas meu problema estava relacionado a um UIView, nãoUIScrollView

self.navigationController.navigationBar.translucent = NO;
user3430340
fonte
2

Apenas lembre-se de que a automaticallyAdjustsScrollViewInsets propriedade funciona apenas se algum tipo de exibição de rolagem (exibição de tabela, exibição de coleção, ...) for

  • A visão do VC, ou
  • Primeira subvisão dessa visualização

Outro sugeriu que ele funcione mesmo que seja a primeira subvisão, mas há outras visualizações de rolagem na hierarquia de visualizações.

EDIT (extensão DIY)

Se você deseja um comportamento semelhante, mesmo que não possa atender a essas condições (por exemplo, uma imagem de plano de fundo abaixo da visualização de rolagem), você pode ajustar as inserções da visualização de rolagem manualmente. Mas por favor, não defina como constante como 44 ou 64 ou mesmo 20, como muitos sugerem em torno do SO. Você nunca sabe o tamanho. Pode haver a notificação de chamada / gps / áudio, a barra de navegação nem sempre precisa ter 44 pts, etc.

Acho que a melhor solução é usar o layoutGuide lengthem didLayoutSubviews:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    scrollView.contentInset = UIEdgeInsets(top: topLayoutGuide.length, left: 0, bottom: 0, right: 0)
    scrollView.scrollIndicatorInsets = scrollView.contentInset
}

Você pode usar o bottomLayoutGuide da mesma maneira.

Vojta Rujbr
fonte
E, obviamente, a barra de navegação é translúcida.
Vojta Rujbr