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

435

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

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

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

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

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

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

Обновить:

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

self.navigationController.navigationBar.translucent = NO;

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

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

beebcon
источник
Я также получаю ту же проблему в xcode 5 DP
Гопеш Гупта
Дайте мне знать, если вы
найдете
1
Посмотрите на панели навигации свойство оттенка цвета, вы должны иметь возможность изменить этот синий цвет на любой, что вы хотите.
beebcon
9
Я ненавижу обновление ios иногда, потому что Apple никогда не давала вам возможность поддерживать ваше приложение обратно совместимым.
Bagusflyer
3
Если проблема связана с видом, идущим под строкой состояния после скрытия верхней панели контроллера навигации, я бы назвал ответ @Stunner stackoverflow.com/a/18976660/235206 как решение
MiKL

Ответы:

495

Вы можете добиться этого, внедрив новое свойство под названием edgesForExtendedLayoutiOS7 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тип, который определяет каждый прямоугольника четырех ребер, в дополнение к не указав ни и все. Используйте, edgesForExtendedLayoutчтобы указать, какие края вида должны быть расширены, независимо от прозрачности полосы. По умолчанию значение этого свойства равно UIRectEdgeAll.

  • extendedLayoutIncludesOpaqueBars

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

  • automaticallyAdjustsScrollViewInsets

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

  • topLayoutGuide, bottomLayoutGuide

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

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

Нанда
источник
2
Он не скомпилируется под iOS6. Я думаю, что это должно быть написано как выполнить селектор ...
Шмидт
8
Да, вот почему я включил проверку селектора с условием if, if ([self RespondsToSelector: @selector (dgeForExtendedLayout)])
Нанда
19
Это не будет работать, если у меня нет панели навигации. В этом случае мой взгляд простирается за строкой состояния ..
Ван Ду Тран
4
У меня та же проблема, что и у @VanDuTran. dgeForExtendedLayout не помогает, если панель навигации скрыта.
рыбий
6
это работает, но ... больше нет полупрозрачного эффекта ... как мы можем также сохранить полупрозрачный эффект ...
Дипу Раджак
110

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

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

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

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

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

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

[self setEdgesForExtendedLayout:UIRectEdgeNone];
Мик МакКаллум
источник
15
Как мне сделать то же самое для простого просмотра в .xib?
bobics
2
Я добавил один ярлык в поле зрения и следовал вашим инструкциям, но это не работает для меня
RMRAHUL
5
@bobics Ответ на вопрос XIB: «Вы не можете». Во всяком случае, не через IB. Подайте радар и надеюсь, что Apple в конечном итоге решит эту проблему.
меммон
Спасибо @ 0x7fffffff, это была просто информация, которую я искал, и была очень полезной.
Кампо
33

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

- (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).

привлекательный
источник
Наконец-то нашел ответ, который на самом деле работает для этого. Хорошая работа!
StuartM
1
Чтобы решить проблему, из-за которой представление контроллера представления отображается под строкой состояния, когда панель навигации скрыта, это код, который привязывает представление под строкой состояния.
MiKL
Примечание: это отодвинет низ вашего обзора за пределы экрана.
меммон
1
Кроме того, если вы собираете только iOS7, приведенный выше код выдаст ошибку - topLayoutGuideтолько iOS7.
меммон
1
Также обратите внимание, что когда ваш основной вид является UITableView, viewDidLayoutSubviews будет вызываться при каждой прокрутке. Ваш UITableView будет уменьшен до 15px. Добавьте флаг, чтобы запускать этот код только один раз. ;)
Томас Йоханнесмейер
30

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

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}
flo_23
источник
Это то, что помогло мне ... так просто. Спасибо :-)
Эрнан Арбер
Спасибо, это действительно полезно
Мухаммед Ахмед
Это лучшее решение для 10.x Swift 3+ IMO
shokaveli
10

Если вы хотите, чтобы представление имело полупрозрачную навигационную панель (что довольно мило), вы должны установить 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);
}
Магнус
источник
3
почему вы не можете напрямую сравнить его с 7.0
Leena
1
Я понял: проверка на конкретную версию с незначительным добавлением менее надежна. Но вы проверяете, является ли значение БОЛЬШИМ или равным так, чтобы сравнение с 7.0 было бы просто замечательно;)
EeKay
1
@leena - это функции в 7.x и более поздних версиях, поэтому я проверяю версию 7 или выше и пропускаю незначительные изменения в проверке.
Магнус
2
У меня возникла проблема с отображением моего tableView за моей вкладкой. Который заставил последний ряд моей таблицы никогда не прокручиваться выше Tabbar. Я исправил это так: myTableView.contentInset = UIEdgeInsetsMake (0, 0.0, TabbarHeight, 0)
Джеймс Лоренстин
contentInsetявляется собственностью UIScrollView. Что делать, если мой основной вид не подкласс UIScrollView. Тогда как бы я исправить проблему с перекрытием?
Pwner
9

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
Радж Паван Гумдал
источник
9

В вашем списке приложений добавьте строку, назовите ее «Просмотр внешнего вида строки состояния на основе контроллера» и установите для нее значение « НЕТ» .

Идан
источник
7

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

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

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

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

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

И результат :

Перед После

Рысков
источник
6
Это работает, но это выглядит как трудно поддерживаемое решение. Было бы лучше просто решить проблему, а не исправлять ее.
NLemay
было бы лучше сделать это программно для всех подпредставлений представления, потому что это не работает, если применить к основному представлению
wildmonkey
5

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

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.edgesForExtendedLayout = UIRectEdge.None
}
fatihyildizhan
источник
4
Теперь это edgeForExtendedLayout = []
Леон
1
Так как это публичный ответ, не забудьте позвонить:super.viewWillAppear(animated)
prodos
4

Я хотел бы расширить ответ 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;
    }
}
werdsackjon
источник
4

Свифт 3

override func viewWillAppear(_ animated: Bool) {
    self.edgesForExtendedLayout = []
}
Шахрукх
источник
3

У меня есть сценарий, в котором я использую 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;
    }
}

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

Ксавье Джон
источник
2

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

  if ([[[UIDevice currentDevice] systemVersion] floatValue]<= 7) {
self.edgesForExtendedLayout = UIRectEdgeNone;
 }
Амит Шелгаонкар
источник
Это единственное, что сработало в моих обстоятельствах.
goobliata
2

сделать ограничения для Top Layout, как это введите описание изображения здесь

carmen_munich
источник
2

Swift 4.2 - Xcode 10.0 - iOS 12.0:

if #available(iOS 11.0, *) {} else {
  self.edgesForExtendedLayout = []
  self.navigationController?.view.backgroundColor = .white
}
juliancadi
источник
1

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

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

Giuseppe
источник
+1, у меня было «Строка состояния изначально скрыта» = ДА, но при добавлении «Просмотр внешнего вида строки состояния на основе контроллера» = НЕТ я избавился от строки состояния.
Йонас Быстрем
1

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

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

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

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

Алексей В.
источник
В моем случае мой основной вид перекрывал мой tabBar, и я понятия не имел, почему. Оказывается, было установлено значение «Расширить края»> «Под нижними панелями». Это было действительно трудно заметить, потому что фон моего приложения был белым, и он только создавал некоторую непрозрачность уровня над моим tabBar. Спасибо!
Иисус Родригес
0

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

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

2.И установить, просмотреть внешний вид строки состояния контроллера: Boolean NO

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

Чандрика
источник
0

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

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

DevB2F
источник