iOS 7: UITableView показывает в строке состояния


первый экран моего приложения UITableViewController без панели навигации, что означает, что содержимое течет под строкой состояния, так что есть много текстовых коллизий. Я настроил оба свойства для Under top bars и Adjust scroll view insets которые на самом деле останавливают его от прокрутки вниз, но за счет сохранения верхней части представления таблицы. Я попытался установить UITableView кадр для смещения на 20 пикселей, но он, похоже, не вступает в силу, и в настоящее время мне нужно, чтобы приложение было совместимо с iOS 6 я не могу перейти на iOS 7 раскадровки, чтобы заставить autolayout использовать руководство по верхней высоте. Кто-нибудь нашел решение, которое работает для обеих версий?

вещи, которые я пробовал: задание edgesForExtendedLayout, изменение настроек в раскадровке для Under top bars и Adjust scroll view, заставляя кадр в новую область.

картинка стоит тысячи слов:

25 207

25 ответов:

для тех, кто заинтересован в тиражировании этого, просто выполните следующие действия:

  1. создать новый проект iOS
  2. откройте основную раскадровку и удалите значение по умолчанию / initial UIViewController
  3. перетащите новый UITableViewController из библиотеки объектов
  4. установите его в качестве начального контроллера вида
  5. накормите таблицу некоторыми тестовыми данными

если вы выполните описанные выше шаги, при запуске приложения, вы увидите, что ничего, в том числе настройка флажков Xcode для "расширения краев под {Top, Bottom, Opaque} Bars" работает, чтобы остановить появление первой строки в строке состояния, и вы не можете решить это программно.

например, в приведенном выше сценарии следующее будет иметь нет эффект:

// These do not work
self.edgesForExtendedLayout=UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars=NO;
self.automaticallyAdjustsScrollViewInsets=NO;

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

Я не согласен со всеми, кто пытается решить эту проблему с помощью любой формы "магических чисел", например "использовать дельту 20px". Такого рода тесно связанное Программирование, безусловно, не то, что Apple хочет, чтобы мы здесь делали.

я нашел два решения этой проблемы:

  • сохранение UITableViewControllerС места:
    Если вы хотите сохранить UITableViewController в раскадровке, без ручного размещения его в другой вид, вы можете встроить UITableViewController на UINavigationController (редактор > встроить в > навигационный контроллер) и снимите флажок "показывает панель навигации" в инспекторе. Это решает проблему без необходимости дополнительной настройки, а также сохраняет свой UITableViewControllerсцена в раскадровке.

  • С помощью автозапуска и встраивания UITableView в другой вид(я считаю, что именно так Apple хочет, чтобы мы это сделали):
    Создать пустой UIViewController и перетащите ваш UITableView в нем. Затем, Ctrl-перетащите из вашего UITableView к строке состояния. Когда мышь попадает в нижнюю часть строки состояния, вы увидите пузырь автозапуска, который говорит "Top Layout Guide". Отпустите кнопку мыши и выберите "вертикальный интервал". Это подскажет системе компоновки разместить его прямо под строкой состояния.

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

если вы делаете вещи программно и с помощью UITableViewController без UINavigationController лучше всего сделать следующее в viewDidLoad:

Swift 3

self.tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)

Ранее Swift

self.tableView.contentInset = UIEdgeInsetsMake(20.0f, 0.0f, 0.0f, 0.0f);

The UITableViewController будет по-прежнему прокручиваться за строку состояния, но не будет под ней при прокрутке вверх.

обратите внимание: это работало для меня для следующей конфигурации:

  • нет панели навигации в верхней части экрана (вид таблицы соответствует строке состояния)
  • вид таблицы не прокручивается

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

Оригинальное Сообщение

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

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

источник (in topLayoutGuide раздел в нижней части страницы.39).

добавление к верхнему ответу:

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

TLDR; 2-е решение верхнего ответа почти работает, но для некоторых версий Xcode ctrl+перетаскивание в "Top Layout Guide" и выбор вертикального интервала ничего не делает. Однако сначала отрегулируйте размер табличного представления, а затем выберите " верхнее пространство для верхнего руководства по компоновке" работает


  1. перетащите пустой ViewController на раскадровку. View Controller

  2. перетащите UITableView объект в поле зрения. (Не UITableViewController). Расположите его в самом центре с помощью синих направляющих макета.

Table ViewCenter Image

  1. перетащите UITableViewCell в TableView. Это будет ваша ячейка повторного использования прототипа, поэтому не забудьте установить ее Повторно используйте идентификатор на вкладке атрибуты или вы получите сбой.

Add Table View CellReuse Identifier

  1. создайте свой собственный подкласс UIViewController и добавьте <UITableViewDataSource, UITableViewDelegate> протоколов. Не забудьте установить ViewController раскадровки в этот класс в Инспекторе идентификации.

  2. создайте выход для вашего TableView в файле реализации и назовите его "таблица"

Create OutlettableView

  1. щелкните правой кнопкой мыши TableView и перетащите как источник данных, так и делегат на ваш ViewController.

dataSource delegate

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

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

resize

  1. теперь вы можете управлять перетаскиванием из табличного представления в верхнюю часть и выбрать Top Space to Top Layout Guide

Top Space to Top Layout Guide

  1. это даст вам ошибку о неоднозначной компоновке TableView, просто добавьте отсутствующие ограничения и ваше дело.

Add Missing Constraints

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

- (void) viewDidLayoutSubviews {
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
        self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
        if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
            self.edgesForExtendedLayout = UIRectEdgeNone;   // iOS 7 specific
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;
        viewBounds.origin.y = topBarOffset * -1;
        self.view.bounds = viewBounds;
        self.navigationController.navigationBar.translucent = NO;
    }
}

https://developer.apple.com/library/ios/documentation/userexperience/conceptual/TransitionGuide/SupportingEarlieriOS.html#//apple_ref/doc/uid/TP40013174-CH14-SW1

вот как это написать в " Swift" Поправка к ответу @ lipka:

tableView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)

выберите UIViewController на раскадровке снимите флажок расширить края под верхней панели. Работать на меня. :)

для Xcode 7, сняв галочку "полупрозрачный" флажок для панели навигации работал для меня.

enter image description here

это исправит его для UITableViewController (без каких-либо магических чисел). Единственное, что я не мог заставить его исправить, это если вы находитесь на телефонном звонке, и в этом случае верхняя часть tableView слишком сильно нажата. Если кто-то знает, как решить эту проблему, пожалуйста, дайте нам знать.

class MyTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()    
        configureTableViewTop()
    }

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        coordinator.animateAlongsideTransition({ (context) -> Void in
            }, completion: { (context) -> Void in
                self.configureTableViewTop()
        })
    }

    func configureTableViewTop() { 
        tableView.contentInset.top = UIApplication.sharedApplication().statusBarFrame.height
    }
}

Я не знаю, насколько это кошерно, но я обнаружил, что эта схема перемещает представление ViewController вниз и предоставляет строку состояния с твердым фоном:

- (void)viewDidLoad {
    [super viewDidLoad];

    // Shove everything down if iOS 7 or later
    float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (systemVersion >= 7.0f) {

        // Move the view down 20 pixels
        CGRect bounds = self.view.bounds;
        bounds.origin.y -= 20.0;
        [self.view setBounds:bounds];

        // Create a solid color background for the status bar
        CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20);
        UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame];
        statusBar.backgroundColor = [UIColor redColor];
        [self.view addSubview:statusBar];
    }

конечно, заменить redColor С любым цветом, который вы хотите для фона.

вы должны отдельно сделать один из поворотов, чтобы установить цвет символов / символов в строке состояния. Я использую View controller-based status bar appearance = NO и Status bar style = Opaque black style в plist, чтобы сделать это глобально.

кажется, работает, и я был бы интересно услышать о каких-либо ошибок или проблем с ним.

ответ chappjc отлично работает при работе с XIBs.

Я нашел самое чистое решение при создании tableviewcontrollers программно, обернув экземпляр UITableViewController в другой UIViewController и установив соответствующие ограничения.

вот это:

UIViewController *containerLeftViewController = [[UIViewController alloc] init];
UITableViewController *tableViewController = [[UITableViewController alloc] init];

containerLeftViewController.view.backgroundColor = [UIColor redColor];

hostsAndMoreTableViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
[containerLeftViewController.view addSubview:tableViewController.view];

[containerLeftViewController addChildViewController:tableViewController];
[tableViewController didMoveToParentViewController:containerLeftViewController];

NSDictionary * viewsDict = @{ @"tableView": tableViewController.view ,
                              @"topGuide": containerLeftViewController.topLayoutGuide,
                              @"bottomGuide": containerLeftViewController.bottomLayoutGuide,
                              };
[containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|"
                                                                                         options:0
                                                                                         metrics:nil
                                                                                           views:viewsDict]];
[containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide][tableView][bottomGuide]"
                                                                                         options:0
                                                                                         metrics:nil
                                                                                           views:viewsDict]];

Ура, Бен

Я думаю, что подход к использованию UITableViewController может немного отличаться от того, что вы делали раньше. Это сработало для меня, но вы не можете быть поклонником этого. То, что я сделал, это иметь контроллер вида с видом контейнера, который указывает на мой UItableViewController. Таким образом, я могу использовать TopLayoutGuide, предоставленный моему в раскадровке. Просто добавьте ограничение в представление контейнера, и вы должны позаботиться как о iOS7, так и о iOS6.

в итоге я использовал один дополнительный вид с желаемым фоном, добавленный после TableView и помещенный в строку состояния:

    self.CoverView = [[UIView alloc]init];

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

    self.CoverView.frame = CGRectMake(0,0,self.view.bounds.size.width,20);
    }

    self.CoverView.backgroundColor = [UIColor whiteColor];
    self.TableView = [[UITableView alloc]initWithFrame:CGRectMake(0,
    self.CoverView.bounds.size.height,XXX, YYY)];
    [self.view addSubview:self.TableView];
    [self.view addSubview:self.CoverView];

это не очень красиво, но это довольно простое решение, если вам нужна работа с xib-менее представлениями, и как IOS6, так и IOS7

Я сделал это для Retina / Non-Retina display как

BOOL isRetina = FALSE;

if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
    if ([[UIScreen mainScreen] scale] == 2.0) {
        isRetina = TRUE;
    } else {
        isRetina = FALSE;
    }
}

if (isRetina) {
    self.edgesForExtendedLayout=UIRectEdgeNone;
    self.extendedLayoutIncludesOpaqueBars=NO;
    self.automaticallyAdjustsScrollViewInsets=NO;
}

следующее решение достаточно хорошо работает в коде без использования магических констант и учитывает изменение пользователем класса размера, например, путем вращения или бок о бок приложений на iPad:

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    [super traitCollectionDidChange:previousTraitCollection];
    // Fix up content offset to ensure the tableview isn't underlapping the status bar.
    self.tableView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0.0, 0.0, 0.0);
}

работает для swift 3-In viewDidLoad ();

let statusBarHeight = UIApplication.shared.statusBarFrame.height

let insets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0)
tableView.contentInset = insets
tableView.scrollIndicatorInsets = insets

этот код: 1. Возвращает высоту строки состояния 2. В верхней части таблицы отображается вставка содержимого, равная высоте строки состояния. 3. Дает индикатору прокрутки ту же вставку, поэтому он появляется под строкой состояния.

У меня был UISearchBar в верхней части моего UITableView и следующее работало;

self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
self.tableView.contentOffset = CGPointMake(0, -20);

поделиться и наслаждаться...

Я получил это работает путем установления размера произвольной формы

enter image description here

Abrahamchez по https://developer.apple.com/library/ios/qa/qa1797/_index.html работал для меня следующим образом. У меня был один UITableviewcontroller в качестве моего первоначального представления. Я попробовал код смещения и встраивание в navcon, но ни один не решил прозрачность строки состояния.

добавьте Viewcontroller и сделайте его начальным видом. Это должно показать вам критические верхние и нижние направляющие макета.

перетащите старый Tableview в представление в новом контроллер.

сделайте все, чтобы обновить таблицу в новый контроллер:

измените свой старый контроллер вида.H файл для наследования / подкласса от UIViewController вместо UITableViewController.

добавьте UITableViewDataSource и UITableViewDelegate в viewcontroller .з.

повторно подключите все необходимое в раскадровке, например панель поиска.

самое главное - настроить ограничения, как в Apple Q&A. я этого не делал потрудитесь вставить панель инструментов. Не уверен в точной последовательности. Но красный значок появился на направляющих макета, возможно, когда я построил. Я щелкнул его и позволил Xcode установить/очистить ограничения.

затем я щелкнул везде, пока не нашел ограничение вертикального пространства и не изменил его верхнее значение от -20 до 0, и он работал отлично.

Я использую UISplitViewController с navigationcontroller и tableviewcontroller. Это сработало для меня в главном представлении после попытки многих решений здесь:

float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion >= 7.0f) {

    // Move the view down 20 pixels
    CGRect bounds = self.view.bounds;
    bounds.origin.y -= 20.0;
    [self.navigationController.view setBounds:bounds];

    // Create a solid color background for the status bar
    CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20);
    UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame];
    statusBar.backgroundColor = [UIColor whiteColor];
    [statusBar setAlpha:1.0f];
    [statusBar setOpaque:YES];
    [self.navigationController.view addSubview:statusBar];
}

это похоже на решение Hot Licks, но применяет подвид к navigationController.

override func viewDidLoad() {
 // your code

 if let nc = self.navigationController {
   yourView.frame.origin.y = nc.navigationBar.frame.origin.y + nc.navigationBar.frame.height
  }
}

вот Swift 2.3. Решение (Xcode версии 8.0). Я создал подкласс UITableView.

class MYCustomTableView: UITableView
{   
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        contentInset    = UIEdgeInsetsZero
    }
}

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

Не забудьте обновить TableView в вашем IB (в TableViewController или просто TableView внутри вашего ViewController).

Я столкнулся с этой проблемой в ios 11, но макет был правильным для ios 8-10.3.3 . Для моего случая я установил ограничение вертикального пространства для Superview.Верхнее поле вместо супервизора.Топ, который работает для ios 8-11.

enter image description here

показать все решения: мой проект просто использует xib, поэтому решение с раскадровкой не сработало для меня. личность.edgesForExtendedLayout = UIRectEdgeNone; просто работает для контроллера, если навигационная панель видна. но если ваше представление просто имеет строку состояния, это не будет работать. так что я совмещаю два условия.

- (void) viewDidLayoutSubviews {
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion >= 7.0f) {
    CGRect bounds = self.view.bounds;
    if(self.navigationController == nil || self.navigationController.isNavigationBarHidden == YES){
        bounds.origin.y -= 20.0;
        [self.view setBounds:bounds];
    }
    else{
        self.edgesForExtendedLayout = UIRectEdgeNone;
    }
}

помогите это работает.

Если вам нужна поддержка iOS 6, вам придется условно переместить его вниз. То есть, в iOS 7 Вы должны просто переместить его вниз на 20 пунктов (либо через frame манипуляция или использование авто-макета), а в iOS 6 Вы оставляете его в покое. Я не верю, что вы можете сделать это в IB, поэтому вам придется сделать это в коде.

EDIT

вы можете сделать это в IB, используя дельты iOS6/iOS7. Установите свою позицию в iOS 7, Затем для iOS 6 Установите delta Y в -20points. Смотрите это так вопрос для получения дополнительной информации.