Объяснение различия между автоматическиAdjustsScrollViewInsets, extendedLayoutIncludesOpaqueBars, edgeForExtendedLayout в iOS7

Я много читал о переходе на iOS7 UI.

Я не могу получить то, что эти три свойства automaticallyAdjustsScrollViewInsets, extendedLayoutIncludesOpaqueBars, edgesForExtendedLayout??

Например, я пытаюсь сделать мои контроллеры представлений ниже строки состояния, но я не могу этого достичь.

Ответ 1

Начиная с iOS7, контроллеры представления по умолчанию используют полноэкранный макет. В то же время у вас есть больший контроль над тем, как он размещает свои представления, и как это делается с этими свойствами:

edgesForExtendedLayout

В основном, с помощью этого свойства вы устанавливаете, какие стороны вашего вида могут быть расширены, чтобы охватить весь экран. Представьте, что вы UIViewController в UINavigationController. Когда представление этого контроллера представления выложено, оно начнется там, где заканчивается панель навигации, но это свойство будет определять, какие стороны вида (верхняя, левая, нижняя, правая) могут быть расширены для заполнения всего экрана.

Давайте посмотрим на это на примере:

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

Здесь вы не устанавливаете значение edgesForExtendedLayout, поэтому берется значение по умолчанию (UIRectEdgeAll), поэтому представление расширяет свой макет, чтобы заполнить весь экран.

Это результат:

without edges for extended layout, the view fills the whole screen

Как видите, красный фон простирается за панелью навигации и строкой состояния.

Теперь вы собираетесь установить это значение на UIRectEdgeNone, поэтому вы говорите контроллеру представления не расширять представление, чтобы покрыть экран:

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

И результат:

with edgesForExtendedLayout set, the view is just under the navigation


automaticallyAdjustsScrollViewInsets

Это свойство используется, когда ваше представление является UIScrollView или аналогичным, например UITableView. Вы хотите, чтобы ваша таблица начиналась там, где заканчивается панель навигации, потому что вы не увидите весь контент, если нет, но в то же время вы хотите, чтобы ваша таблица покрывала весь экран при прокрутке. В этом случае установка edgesForExtendedLayout в None не будет работать, потому что ваша таблица будет начать прокрутку, где панель навигации заканчивается, и он не пойдет за ним.

Вот где это свойство пригодится, если вы позволите контроллеру представления автоматически корректировать вставки (устанавливая это свойство в YES, также значение по умолчанию), он добавит вставки в верхнюю часть таблицы, поэтому таблица начнется там, где происходит навигация. полоса заканчивается, но прокрутка покроет весь экран.

Это когда НЕТ:

the table will scroll over the whole screen, but starts out partially covered

И ДА (по умолчанию):

the table scrolls over the whole screen, and starts just under the navigation

В обоих случаях таблица прокручивается за панелью навигации, но во втором случае (ДА) она запускается из-под панели навигации.


extendedLayoutIncludesOpaqueBars

Это значение является лишь дополнением к предыдущим. По умолчанию для этого параметра установлено значение NO. Если строка состояния непрозрачна, представления не будут расширены, чтобы включить строку состояния, даже если вы расширили представление, чтобы покрыть его (edgesForExtendedLayout до UIRectEdgeAll).

Если вы установите значение YES, это позволит представлению снова перейти под строку состояния.

Если что-то не понятно, напишите комментарий и я на него отвечу.

Как iOS узнает, что использовать UIScrollView?

iOS захватывает первое подпредставление в вашем представлении ViewController, которое имеет индекс 0, и, если оно является подклассом UIScrollView то применяет к нему объясненные свойства.

Конечно, это означает, что UITableViewController работает по умолчанию (поскольку UITableView является первым представлением).

Ответ 2

Не уверен, что вы используете раскадровки, но если вы хотите, чтобы ваши контроллеры представлений начинались ниже строки состояния (и над нижней панелью):

Выберите контроллер вида в IB, В инспекторе атрибутов снимите флажок "Расширять края - под верхними барами" и "Расширить края - под нижними границами".

Ответ 3

Я использую раскадровки и используя приведенный выше совет, однако я не был точно уверен, как его реализовать. Ниже приведен краткий пример того, как он устраняет проблему, помещая рекомендуемое решение в 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.
  }

}

Моя проблема: Автоматическая настройка установлена ​​на значение true по умолчанию, что вызывает разницу между дизайном раскадровки и симулятором Auto Adjust set to true by default causing a difference between storyboard design and simulator

Решено: Приведенный выше код, отключив автонастройку. Code above applied, turning off the auto-adjust.

Ответ 4

Я решил эту проблему, добавив эту строку, но моя проблема была связана с UIView, а не UIScrollView

self.navigationController.navigationBar.translucent = NO;

Ответ 5

Просто помните, что automaticallyAdjustsScrollViewInsets свойство работает только в том случае, если какой-либо вид прокрутки (просмотр таблицы, просмотр коллекции,...) является либо

  • Вид VC или
  • Первое представление этого представления

Другие предположили, что он работает, даже если он является первым подвью, но в иерархии представлений есть другие виды прокрутки.

EDIT (расширение DIY)

Если вам нужно подобное поведение, даже если вы не можете выполнить эти условия (например, у вас есть фоновое изображение ниже прокрутки), вы можете вручную отредактировать вставки прокрутки. Но, пожалуйста, не устанавливайте его на постоянное, как 44 или 64 или даже 20, как многие предлагают вокруг. Вы никогда не знаете размер. Может быть уведомление incall/gps/audio, на навигационной панели не должно быть всегда 44 очка и т.д.

Я думаю, лучшим решением является использование layoutGuide length в didLayoutSubviews:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

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

Вы можете использовать метод bottomLayoutGuide таким же образом.