строка состояния и панель навигации отображаются неправильно в iPhoneX

У меня есть контроллер «о программе», использующий панель навигации под строкой состояния. По какой-то причине я должен установить цвет фона View таким же цветом, как и панель навигации, иначе фон строки состояния будет белым. Этот трюк отлично работает на другом устройстве, но не на iPhoneX с альбомной ориентацией. Как вы видите ниже: введите здесь описание изображения

Если я установлю фон View белым, возникнут другие проблемы:

1) Строка состояния белая. введите здесь описание изображения

2) Панель навигации не расширяется в альбомной ориентации введите здесь описание изображения

Похоже, это проблема, связанная с тем, что у меня есть панель навигации внутри представления, поскольку структура раскадровки показана ниже:

введите здесь описание изображения

Но я не могу переместить панель навигации на тот же уровень, что и вид. Есть идеи?


person Adam C.    schedule 09.03.2018    source источник


Ответы (5)


Ваш UINavigationBar, скорее всего, прикреплен к safeAreas представления. Здесь нужно учитывать несколько вещей:

Текущая настройка

В настоящее время ваше представление закреплено на вкладках безопасной области его суперпредставления. На iPhone X это:

  • UIEdgeInsets(top: 44, left: 0, bottom: 34, right: 0) в Портрет
  • UIEdgeInsets(top: 0, left: 44, bottom: 21, right: 44) в Пейзаж

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

введите описание изображения здесь введите здесь описание изображения

Значения в safeAreaInsets.bottom здесь не имеют значения, потому что navigationBar, скорее всего, не будет расширяться так далеко до нижней части своего супервизора.



Закрепление в супервизоре

Хорошо, теперь давайте прикрепим представление к краям его суперпредставления, а не к вставке безопасной области:

введите здесь описание изображения (сделайте это для всех трех краев, при необходимости изменив константу на 0)

Вот что у нас получается:

введите описание изображения здесь введите здесь описание изображения

Выглядит хорошо для пейзажа, но что не так с портретом? Обратите внимание, как кнопка панели находится внутри строки состояния. Что ж, система компоновки делает именно то, что вы ей говорите (если бы это было правдой все время, кодирование для iOS было бы проще простого :D). Он прикрепляет представление к самому верху своего суперпредставления, игнорируя любые layoutMargin или safeAreaInsets. Однако для UINavigationBar это не то, что нам нужно. Мы хотим, чтобы содержимое строки начиналось с любого safeAreaInset.top, чтобы оно, например, не мешало строке состояния.



Решение

Решение состоит в том, чтобы вернуть верхнее ограничение обратно к «относительно safeArea». Содержимое панели навигации теперь выглядит нормально. Чтобы расширить фон navigationBar вверх, вы устанавливаете делегат navigationBars (UINavigationBarDelegate) и предоставляете следующую реализацию:

func position(for bar: UIBarPositioning) -> UIBarPosition {
  return .topAttached
}

Возвращая .topAttached, вы указываете панели навигации расширять фон (размытие) вверх под строкой состояния.

Результат:

введите описание изображения здесь

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



Приложение

Несколько дополнительных замечаний по этой теме:

  • Нам не нужно рассматривать левую и правую безопасные области здесь. UINavigationBar учитывает их и соответствующим образом вставляет свое содержимое. Это не работает для вертикальных вставок, поэтому мы должны проделать танец, описанный выше.
  • Если присмотреться, то даже расположение на самой последней картинке не совсем правильное. Большой заголовок расположен слишком близко к левому краю. Чтобы обойти это, вам нужно будет отметить Preserve Superview Margins для панели навигации в раскадровке. Опять же, все эти вещи обрабатываются системой за вас, если вы просто используете UINavigationController в первую очередь.
person CodingMeSwiftly    schedule 12.03.2018
comment
Вы спасли мой день! - person adnako; 26.03.2019

Вы можете использовать два представления, одно для строки состояния, а другое для панели навигации, и применить ограничение, как показано, и ваша проблема будет исправлена.

Применить ограничения

введите здесь описание изображения

введите здесь описание изображения

person Anup Kanjariya    schedule 12.03.2018

isTranslucent по умолчанию установлено на true. Установка его на false расширит панель навигации ниже строки состояния.

navigationBar.isTranslucent = false
person Dejan Atanasov    schedule 14.09.2019

Резюме и небольшое объяснение для начинающих для ответа CodingMeSwiftly:

  1. В вашем классе ViewController в методе viewDidLoad или аналогичном вы должны назначить делегата (или сделать это в раскадровке):

    navigationBar.delegate = self //где navigationBar — это IBOutlet

  2. Сделайте расширение для вашего класса ViewController:

    extension ViewController: UINavigationBarDelegate { func position (для бара: UIBarPositioning) -> UIBarPosition { return .topAttached}}

  3. Убедитесь, что на раскадровке верхним ограничением панели навигации является Safe Area.Top.

Меня устраивает.

person VyacheslavB    schedule 03.09.2020

Похоже, что автономная панель навигации просто не работает для этого случая. После изменения его на элемент навигации проблема устранена. Чтобы сделать его элементом навигации, я выбираю существующий контроллер (тот, что с панелью навигации) и встраиваю его в контроллер навигации через «Редактор -> Встроить».

person Adam C.    schedule 12.03.2018