it-swarm.com.ru

iOS 7: UITableView отображается под строкой состояния

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

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

Одна картинка стоит тысячи слов: Status bar flow under

216
Nicholas Smith

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

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

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

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

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

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

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

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

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

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

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

364
marinosb

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

Свифт 3

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

Ранее Свифт

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

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

84
lipka

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

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

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

Исходное сообщение

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

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

23
Stunner

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

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

TLDR; второе решение верхнего ответа почти работает, но для некоторых версий xCode ctrl + перетаскивание в "Руководство по верхнему макету" и выбор вертикального интервала ничего не дает. Однако сначала нужно отрегулировать размер табличного представления, а затем выбрать Работает "Руководство по макету сверху наверх"


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

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

Table ViewCenter Image

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

Add Table View CellReuse Identifier

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

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

Create OutlettableView

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

dataSource delegate

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

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

resize

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

Top Space to Top Layout Guide

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

Add Missing Constraints

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

20
ErikAGriffin
- (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

11
Olzh

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

tableView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
8
uplearnedu.com

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

7
pegpeg

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

enter image description here

5
David T

Это исправит это для 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
    }
}
3
Harris

ответ chappjc прекрасно работает при работе с XIB.

Я обнаружил, что самое чистое решение при создании 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]];

Ура, Бен

2
tubtub

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

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

2
Hot Licks

Я сделал это для отображения Retina/Non-Retina как

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;
}
1
Salim

Для таких, как я, которые предпочли бы не вставлять свои UITableViewController в UIViewController, попробуйте это:

Пользовательский подкласс UITableViewController может добавить представление маски к суперпредставлению tableView. Добавьте маску в viewDidAppear и удалите маску в viewWillDisappear.

private var statusBarMaskView: UIView!

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if let superview = self.tableView.superview {
        self.statusBarMaskView = UIView(frame: CGRect.zero)
        superview.insertSubview(self.statusBarMaskView, aboveSubview: self.tableView)
        self.statusBarMaskView.backgroundColor = self.tableView.backgroundColor

        // using a Nice constraint layout library to set the frame
        self.statusBarMaskView.pinTop(to: superview)
        self.statusBarMaskView.pinLeft(to: superview)
        self.statusBarMaskView.pinRight(to: superview)
        self.statusBarMaskView.addHeightConstraint(with: 22.0)
        ////
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.statusBarMaskView.removeFromSuperview()
    self.statusBarMaskView = nil
}
1
Lee Irvine

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

1
Phong Le

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

- (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);
}
1
qix

В итоге я использовал один дополнительный вид с нужным фоном, добавленный после 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

1
lilislilit

Работает для Swift 3 - в 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. Придает индикатору прокрутки ту же вставку, чтобы он отображался под строкой состояния.

1
Wesh RaphLola

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

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

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

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

Измените старый файл view controller.h, чтобы он наследовал/подкласс от UIViewController вместо UITableViewController.

Добавьте UITableViewDataSource и UITableViewDelegate в .h контроллера вида.

Повторно подключите все, что нужно в раскадровке, например, панель поиска.

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

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

0
Jack Bellis

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

enter image description here

0
DareDevil

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

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

Поделитесь и наслаждайтесь ...

0
Sam T
override func viewDidLoad() {
 // your code

 if let nc = self.navigationController {
   yourView.frame.Origin.y = nc.navigationBar.frame.Origin.y + nc.navigationBar.frame.height
  }
}
0
wajih

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

enter image description here

0
fengd

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

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

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

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

0
Darkwonder

Я использую UISplitViewController с навигационным контроллером и 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.

0
sfr14