Строка состояния и панель навигации отображаются за пределами моего представления в iOS 7

Я недавно загрузил Xcode 5 DP для тестирования своих приложений в iOS 7. Первое, что я заметил и подтвердил, это то, что границы моего представления не всегда изменяются с учетом строки состояния и панели навигации.

В viewDidLayoutSubviewsЯ печатаю границы представления:

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

В результате мой контент появляется под панелью навигации и строкой состояния.

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

Как я могу исправить эту проблему?

Обновить:

Я нашел решение для этой конкретной проблемы. Установите для полупрозрачного свойства панели навигации значение NO:

self.navigationController.navigationBar.translucent = NO;

Это предотвратит отображение вида под панелью навигации и строкой состояния.

Однако я не нашел исправления для случая, когда вы хотите, чтобы панель навигации была полупрозрачной. Например, при просмотре фотографии в полноэкранном режиме, я хочу, чтобы панель навигации была полупрозрачной, а вид под ней был обрамлен. Это работает, но когда я переключаю показ / скрытие панели навигации, я получаю еще более странные результаты. Первое подпредставление (UIScrollView) получает свои границы и происхождение меняется каждый раз.

20 ответов

Решение

Вы можете добиться этого, внедрив новое свойство под названием edgesForExtendedLayout в iOS7 SDK. Пожалуйста, добавьте следующий код для достижения этой цели,

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

Вы должны добавить выше в вашем -(void)viewDidLoad метод.

В iOS 7 внесены некоторые изменения в макет и настройку внешнего вида вашего пользовательского интерфейса. Изменения в макете контроллера представления, цвете оттенка и шрифте влияют на все объекты UIKit в вашем приложении. Кроме того, усовершенствования API распознавания жестов обеспечивают более точный контроль над взаимодействиями жестов.

Использование контроллеров представления

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

wantsFullScreenLayout свойство контроллера представления устарело в iOS 7. Если вы в настоящее время указываете wantsFullScreenLayout = NOКонтроллер представления может отображать свой контент в неожиданном месте на экране, когда он работает в iOS 7.

Чтобы настроить, как контроллер представления выкладывает свои представления, UIViewController предоставляет следующие свойства:

  • edgesForExtendedLayout

edgesForExtendedLayout свойство использует UIRectEdge тип, который определяет каждое из четырех ребер прямоугольника, в дополнение к указанию none и all. использование edgesForExtendedLayout указать, какие края вида должны быть расширены, независимо от прозрачности полосы. По умолчанию значение этого свойства UIRectEdgeAll,

  • extendedLayoutIncludesOpaqueBars

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

  • automaticallyAdjustsScrollViewInsets

Если вы не хотите, чтобы вставки содержимого представления прокрутки автоматически настраивались, установите automaticallyAdjustsScrollViewInsets в NO. (Значение по умолчанию automaticallyAdjustsScrollViewInsets это ДА.)

  • topLayoutGuide, bottomLayoutGuide

topLayoutGuide а также bottomLayoutGuide свойства указывают расположение верхней или нижней кромок панели в представлении контроллера представления. Если столбцы должны перекрывать верхнюю или нижнюю часть представления, вы можете использовать Интерфейсный Разработчик, чтобы расположить представление относительно панели, создавая ограничения в нижней части окна. topLayoutGuide или к вершине bottomLayoutGuide. (Если ни один столбец не должен перекрывать вид, нижняя часть topLayoutGuide такой же, как верхняя часть вида и верхняя часть bottomLayoutGuide совпадает с нижней частью представления.) Оба свойства лениво создаются по запросу.

Пожалуйста, обратитесь, Apple Doc

Вам не нужно вычислять, как далеко все сдвинуть вниз, для этого есть встроенное свойство. В Интерфейсном Разработчике выделите ваш контроллер представления, а затем перейдите к инспектору атрибутов. Здесь вы увидите несколько флажков со словами "Расширить края". Как вы можете видеть, на первом снимке экрана выбор по умолчанию - отображение контента под верхней и нижней полосами, а не под непрозрачными полосами, поэтому настройка стиля полосы на непрозрачный работает для вас.

Как вы можете увидеть на первом скриншоте, под панелью навигации скрываются два элемента пользовательского интерфейса. (Я включил каркасы в IB, чтобы проиллюстрировать это). Эти элементы, UIButton и UISegmentedControl, имеют свое начало "y", установленное в ноль, и контроллер представления установлен, чтобы разрешить содержание ниже верхней панели.

Этот второй снимок экрана показывает, что происходит, когда вы снимаете флажок "Under Top Bars". Как вы можете видеть, представление контроллеров представления было смещено соответствующим образом, чтобы его начало координат y находилось прямо под панелью навигации.

Это также может быть достигнуто программно с помощью -[UIViewController edgesForExtendedLayout], Вот ссылка на ссылку на класс для edgeForExtendedLayout и для UIRectEdge

[self setEdgesForExtendedLayout:UIRectEdgeNone];

Я создал свой вид программно, и это сработало для меня:

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

Источник (в разделе topLayoutGuide внизу стр.39).

Решение Swift 3 / Swift 4, которое также работает с файлами NIB /XIB в iOS 10+:

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}

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

Вот как я это делаю:

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

edgesForExtendedLayout делает то же самое для iOS 7. Однако, если вы создаете приложение в iOS 7 SDK и развертываете его в iOS 6, панель навигации выглядит полупрозрачной, и виды переходят под нее. Итак, чтобы исправить это как для iOS 7, так и для iOS 6, сделайте следующее:

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

В свой plist-файл приложения добавьте строку, назовите ее "Просмотр внешнего вида строки состояния на основе контроллера" и установите для нее значение " NO".

Самый простой трюк - открыть файл NIB и выполнить эти два простых шага:

  1. Просто переключите это и установите тот, который вы предпочитаете:

  1. Выберите те UIView /UIIMageView /..., которые вы хотите переместить вниз. В моем случае только логотип был перекрыт, и я установил дельту на +15; (ИЛИ -15, если вы выбрали iOS 7 на шаге 1)

И результат:

ДоПосле

Быстрое решение:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.edgesForExtendedLayout = UIRectEdge.None
}

Свифт 3

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

Я хотел бы расширить ответ Stunner и добавить if заявление, чтобы проверить, является ли это iOS-7, потому что, когда я проверял это на iOS 6, мое приложение зависало.

Дополнение будет добавлять:

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

Поэтому я бы предложил добавить этот метод в ваш MyViewControler.m файл:

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

У меня есть сценарий, в котором я использую BannerViewController, написанный Apple для отображения моих объявлений, и ScrollViewController, встроенный в BannerViewController.

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

1) Изменить BannerViewController.m

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

2) Изменить мой ScrollViewContoller

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

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

Сделать ограничения для Top Layout, как это

Просто установите следующий код в поле зрения появится.

  if ([[[UIDevice currentDevice] systemVersion] floatValue]<= 7) {
self.edgesForExtendedLayout = UIRectEdgeNone;
 }

Swift 4.2 - Xcode 10.0 - iOS 12.0:

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

Добавьте ключ "Просмотреть внешний вид строки состояния на основе контроллера" из выпадающего списка в виде строки в info.plist, Что-то вроде этого:

Для меня самое простое решение - добавить два ключа в список.

У меня была та же проблема с моим приложением на iPad (armv7, armv7s, amr64) только при представлении другого UIViewController, и после их отклонения появляется панель навигации под строкой состояния... Я трачу много времени, чтобы найти какое-либо решение для этого. Я использую раскадровку и в InterfaceBuilder для UIViewController, который делает ужасно, я устанавливаю презентацию из FullScreen -> Current Context, и это решает эту проблему. Это работает в моем приложении только для iPad => iOS8.0 (тестирование с iOS8.1) и для iPad с iOS 7.1 не работает!! смотреть скриншот

В моем случае прерывание loadView()
этот код: self.edgesForExtendedLayout = UIRectEdgeNone

но после удаления loadView() все работало нормально

Шаги для скрытия строки состояния в iOS 7:

1. Перейдите в файл приложения info.plist.

2.И установить, просмотреть внешний вид строки состояния контроллера: логическое НЕТ

Надеюсь, я решил проблему со статусной строкой.....

Другие вопросы по тегам