Выяснение проблемы initWithFrame:self.view.frame 20 пикселей (строка состояния) раз и навсегда

#ios #uiviewcontroller #frame

#iOS #uiviewcontroller #кадр

Вопрос:

У меня есть простой UINavigationController. В методе init я создаю и добавляю UITableView в качестве подвида.

 - (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromCGRect(self.view.frame)); // {{0, 20}, {320, 460}}
        tableView = [[UITableView alloc] initWithFrame:self.view.frame];
        [self.view addSubview:tableView];
    }
    return self;
}
  

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

Почему в итоге я получаю {{0, 20}, {320, 460}} для self.view.frame? Я не хочу принудительно использовать фрейм CGRect, я бы предпочел установить его на основе фрейма контроллера просмотра, чтобы не возникало проблем с динамическими изменениями фрейма (привязка, телефонный звонок и т.д. где строка состояния выше).

Обновление: Также заметил, что я получаю высоту кадра 460. Это тоже не имеет смысла. В моем случае у меня действительно есть панель вкладок, поэтому высота не должна быть минус строка состояния, минус панель uinavigationbar и минус высота панели вкладок?

Спасибо

Комментарии:

1. поскольку высота строки состояния 20 пикселей

Ответ №1:

Фрейм UIView принимает допустимые аргументы только при вызове -viewWillAppear , -viewDidAppear методов. Вы не должны полагаться на frame и выполнять какие-либо вычисления, используя его раньше.
Также вам не следует использовать view свойство UIViewController (UITableViewController) (из других объектов) перед вызовом -viewDidLoad метода, поэтому вам не следует использовать view и добавлять к нему какие-либо контроллеры в init методе, только в -loadView или (лучше) в -viewDidLoad . Добавьте свой вложенный просмотр в эти методы и установите его рамку перед отображением.
В режиме жизненного цикла ViewController представление может загружаться и выгружаться много раз (например, didReceiveMemoryWarning выгружает представление), представление вообще никогда не может загружаться.

Ответ №2:

Вы смешиваете две разные системы координат. рамка self.view определяется в системе координат окна (или какой бы она ни была в родительском представлении). Рамка TableView определена в системе координат self.view.

Если вы хотите, чтобы что-то заполнило весь вид, установите

 subView.frame = parentView.bounds;
  

границы определяются в собственной системе координат вида. фрейм определяется в системе координат родительского представления. Итак, subView.frame и parentView.bounds — это одна и та же система координат.

При настройке subview.frame = parentView.frame они в конечном итоге не будут одинаковыми более чем на 20 грамм = 20 унций. Основной вид имеет начало отсчета в (0, 20); вспомогательный вид имеет начало отсчета в (0, 20), но в другой системе координат. В системе координат окна это (0, 40).

Комментарии:

1. Да, спасибо. И действительно, именно так это задокументировано в документах Apple iOS для разработчиков: ссылка на класс UIView > Свойства> «границы» и «рамка».