Установка метки для tableFooterView UITableView - с автомакетом

Когда мое табличное представление пусто, я хочу добавить простую метку в нижний колонтитул табличного представления, чтобы отобразить сообщение «нет содержимого». Он работал нормально, когда я устанавливал кадры UILabel и UIView, которые я использовал для нижнего колонтитула, но теперь я пытаюсь преобразовать его в использование автоматического макета, и я не могу заставить его работать.

Вот что я делаю:

// Create the footer    
UIView *tempFooter = [[UIView alloc] init];
UILabel *atext = [[UILabel alloc] init];
tempFooter.translatesAutoresizingMaskIntoConstraints = NO;
atext.translatesAutoresizingMaskIntoConstraints = NO;

atext.numberOfLines = 0;
[atext setText:@"Add Some Text"];
atext.textAlignment = NSTextAlignmentCenter;
atext.font = [UIFont italicSystemFontOfSize:14];
atext.textColor = [UIColor grayColor];
atext.backgroundColor = [UIColor clearColor];
atext.lineBreakMode = NSLineBreakByWordWrapping;

// add label to footer view, and add constraints
[tempFooter addSubview:atext];
NSLayoutConstraint *tvatt1 = [NSLayoutConstraint constraintWithItem:tempFooter
                                                          attribute:NSLayoutAttributeLeft
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:atext attribute:NSLayoutAttributeLeft
                                                         multiplier:1.0
                                                           constant:10.0];

NSLayoutConstraint *tvatt2 = [NSLayoutConstraint constraintWithItem:tempFooter
                                                          attribute:NSLayoutAttributeRight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:atext
                                                          attribute:NSLayoutAttributeRight
                                                         multiplier:1.0
                                                           constant:10.0];

NSLayoutConstraint *tvatt3 = [NSLayoutConstraint constraintWithItem:tempFooter
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:atext
                                                          attribute:NSLayoutAttributeTop
                                                         multiplier:5.0
                                                           constant:0];

NSLayoutConstraint *tvatt4 = [NSLayoutConstraint constraintWithItem:tempFooter
                                                          attribute:NSLayoutAttributeBottom
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:atext
                                                          attribute:NSLayoutAttributeBottom
                                                         multiplier:1.0
                                                           constant: 0];

[tempFooter addConstraints: @[tvatt1, tvatt2, tvatt3, tvatt4]];


// set the footerview 
self.tview.tableFooterView = tempFooter;

Когда я запускаю это, я получаю сбой:

08.09.2014 19:57:16.594 SimpleList[49442:60b] * Ошибка утверждения в -[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794 08.09.2014 19 :57:21.073 SimpleList[49442:60b] * Завершение работы приложения из-за необработанного исключения «NSInternalInconsistencyException», причина: «После выполнения -layoutSubviews все еще требуется автоматическая компоновка. Реализация UITableView -layoutSubviews должна вызывать super

Я не уверен, что я делаю неправильно. Я также пытался установить ограничения для self.tview.tableFooterView по отношению к tempFooter (закрепление со всех 4 сторон), но это не меняет сбой. Я также звоню:

[self.tview.tableFooterView layoutSubviews];

но и это не помогает.

Любые идеи, что я делаю неправильно?


person Z S    schedule 09.09.2014    source источник
comment
Попробуйте закомментировать строку tempFooter.translatesAutoresizingMaskIntoConstraints = NO; и посмотрите, решит ли это проблему.   -  person rdelmar    schedule 09.09.2014
comment
Нет, к сожалению, это приводит к другому сбою: 2014-09-08 22:46:19.905 Невозможно одновременно удовлетворить ограничения. Вероятно, по крайней мере одно из ограничений в следующем списке вам не нужно.... ( ‹NSLayoutConstraint:0x117137d80 V:[UIView:0x10dfd5170(17)]›, ‹NSAutoresizingMaskLayoutConstraint:0x117082480 h=--& v= --& V:[UIView:0x10dfd5170(0)]› )   -  person Z S    schedule 09.09.2014
comment
Эта новая ошибка вызвана тем, что для представления нижнего колонтитула не задана высота (поэтому она будет равна 0), но есть ограничения на его верх и низ для метки с ненулевой высотой. Смотрите мой ответ.   -  person rdelmar    schedule 09.09.2014


Ответы (4)


Вы не должны устанавливать для translatesAutoresizingMaskIntoConstraints значение NO для представлений таблиц, их ячеек или представлений верхнего и нижнего колонтитула таблицы (или для self.view вашего контроллера, если на то пошло). Можно использовать ограничения для представлений внутри этих представлений (представление содержимого ячеек или представления верхнего и нижнего колонтитула). Я добавил упрощенную версию вашего кода в viewDidLoad, и она работала, как и ожидалось. Обратите внимание, что вам нужно указать для нижнего колонтитула высоту и позицию x (позиция y и ширина игнорируются),

    UIView *tempFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 50)];
    UILabel *atext = [[UILabel alloc] init];
    atext.translatesAutoresizingMaskIntoConstraints = NO;
    atext.numberOfLines = 0;
    [atext setText:@"Add Some Text"];
    atext.textAlignment = NSTextAlignmentCenter;
    atext.font = [UIFont italicSystemFontOfSize:14];
    atext.textColor = [UIColor grayColor];
    atext.backgroundColor = [UIColor clearColor];
    atext.lineBreakMode = NSLineBreakByWordWrapping;

    [tempFooter addSubview:atext];
    NSDictionary *dict = NSDictionaryOfVariableBindings(atext);
    [tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[atext]-10-|" options:0 metrics:nil views:dict]];
    [tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[atext]|" options:0 metrics:nil views:dict]];
    self.tableView.tableFooterView = tempFooter;

Я не уверен, чего вы пытались добиться своим ограничением, tvatt3. Множитель (у вас есть 5) ничего не делает с верхним или левым ограничением, поскольку значение этих атрибутов равно 0. Я использовал визуальные ограничения, а не метод, который вы использовали, но когда я использовал ваш код для добавления ограничений , тоже работало.

person rdelmar    schedule 09.09.2014
comment
Спасибо. Множитель на 5 — опечатка (должно быть 1). Кажется, это работает, но есть большая проблема, это то, что высота фиксирована на 50. Как мне отрегулировать высоту заголовка, если текст намного длиннее? например попробуйте так: [atext setText:@"Add Some Text. Now add a lot more text with newlines thrown in for good measure. Does this work beyond a certain height?\n\nNow how do you calculate the height?"]; Полный нижний колонтитул больше не отображается. Я пытался использовать [atext systemLayoutSizeFittingSize: UILayoutFittingExpandedSize], чтобы установить рамку для нижнего колонтитула перед его установкой, но он вылетает. - person Z S; 10.09.2014
comment
Я думаю, что у меня это работает; Я установил нижний колонтитул в viewWillLayoutSubviews и установил высоту нижнего колонтитула, используя systemLayoutSizeFittingSize:. Единственная проблема: в отладчике по-прежнему появляется сообщение Невозможно одновременно удовлетворить ограничения. Это выглядит подозрительно, но я понятия не имею, как оно туда попало: ‹NSLayoutConstraint:0x7fa2d0050d20 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fa2d005acb0(0)]› - person Z S; 10.09.2014
comment
Разобрался: визуальное ограничение для закрепления метки по горизонтали не работало. Я удалил это и добавил ограничение центрирования с limitedWithItem между меткой и tempFooter (с NSLayoutAttributeCenterX), и это работает! - person Z S; 10.09.2014
comment
Можете ли вы объяснить, почему не следует устанавливать translatesAutoresingMaskIntoConstraints? Спасибо - person Lorenzo B; 12.09.2015
comment
@rdelmar Обратите внимание, что вам нужно указать для нижнего колонтитула высоту и позицию x (позиция y и ширина игнорируются) — на самом деле, по крайней мере, в iOS 9 переданная ширина не игнорируется и используется для установки ширина обзора. - person Evan R; 14.06.2016

Интересно, что изменение маски автоматического изменения размера в xib решило мою проблему.

Ограничения не работают:

Не работает

Работающий:

Работает

person Phil Loden    schedule 09.12.2016
comment
После буквально нескольких часов попыток попробовать разные вещи это решило мою проблему как для нижнего колонтитула, так и для верхнего колонтитула файла UITableView. Большое спасибо! Я бы никогда не подумал об этом. - person ishegg; 15.03.2019

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

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if let tableFooter = tableView.tableFooterView {
        let maxSize = CGSize(width: self.tableView.bounds.size.width,
                             height: CGFloat.greatestFiniteMagnitude)
        let size = tableFooter.systemLayoutSizeFitting(maxSize)
        let height = size.height
        var headerFrame = tableFooter.frame

        // If we don't have this check, viewDidLayoutSubviews() will get
        // repeatedly, causing the app to hang.
        if height != headerFrame.size.height {
            headerFrame.size.height = height
            tableFooter.frame = headerFrame
            tableView.tableFooterView = tableFooter
        }
    }
}

PS Я предпочитаю Interface Builder для настройки ограничений введите здесь описание изображения

person Paulius Vindzigelskis    schedule 10.02.2017

Надеюсь, что это поможет вам

Я не уверен в этом, но это помогает мне в моем проекте, сначала добавьте все в contentView (все подвиды и ограничения)

 [self.contentView addSubview:atext]

а затем переходит к части кода

NSLayoutConstraint *tvatt1 = [NSLayoutConstraint constraintWithItem:tempFooter
                                                          attribute:NSLayoutAttributeLeft
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:atext attribute:NSLayoutAttributeLeft
                                                         multiplier:1.0
                                                           constant:10.0]; 

код, говорящий для левого атрибута

 temfooter(must be equal) = 1.0*atext +10.0 

т.е. tempfooter должен быть равен измененному atext , поэтому необходимо убедиться, что ваши ограничения неверны.

person Anurag Bhakuni    schedule 09.09.2014
comment
Спасибо, но вопрос больше о tableFooterView UITableView. Общий вариант использования добавления представления в другой UIView достаточно прост. - person Z S; 09.09.2014
comment
@ZS изучите эту ссылку (constraints.icodeforlove.com), возможно, она вам как-то поможет. - person Anurag Bhakuni; 11.09.2014