Проблема с ограничениями автоматической компоновки на iOS7 в UITableViewCell

Я использую автоматические ограничения компоновки программно для компоновки своих пользовательских ячеек UITableView, и я правильно определяю размеры ячеек в tableView:heightForRowAtIndexPath:

Он отлично работает на iOS6, и он отлично выглядит в iOS7, а также

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

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2013-10-02 09:56:44.847 Vente-Exclusive[76306:a0b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
        "<NSLayoutConstraint:0xac4c5f0 V:|-(15)-[UIImageView:0xac47f50]   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
        "<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>",
        "<NSLayoutConstraint:0xac43680 V:[UIView:0xac4d0f0(1)]>",
        "<NSLayoutConstraint:0xac436b0 V:[UIView:0xac4d0f0]-(0)-|   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>

И действительно, мне не нужно одно из ограничений в этом списке:

"<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"

и я не могу установить для свойства translatesAutoresizingMaskIntoConstraints contentView значение NO = > , это испортит всю ячейку.

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

В iOS6 это не происходит, и все отлично выглядит как на iOS6, так и на iOS7.

Мой код довольно большой, поэтому я не буду публиковать его здесь, но не стесняйтесь спрашивать пастебин, если он вам нужен.

Чтобы указать, как я это делаю, при инициализации ячейки:

  • Я создаю все свои ярлыки, кнопки и т.д.
  • Я установил для своего свойства translatesAutoresizingMaskIntoConstraints значение NO
  • Я добавляю их как подпункты contentView ячейки
  • Я добавляю ограничения на contentView

Мне также очень интересно понять, почему это происходит только на iOS7.

Ответ 1

У меня также возникла эта проблема.. Похоже, что кадр contentView не обновляется до тех пор, пока не будет вызван layoutSubviews, однако кадр ячейки обновляется ранее, оставив кадр contentView в {0, 0, 320, 44} в то время, когда ограничения оцениваются.

После более подробного просмотра contentView, похоже, что autoresizingMasks больше не устанавливаются.

Настройка маски autoresizingMask до того, как вы ограничите свои представления, может решить эту проблему:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self)
    {
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        [self loadViews];
        [self constrainViews];
    }
    return self;
}

Ответ 2

По-видимому, что-то не так с UITableViewCell и UICollectionViewCell на iOS 7 с помощью IOS 8 SDK.

Вы можете обновить содержимое CellView при повторном использовании ячейки следующим образом:

Для статического UITableViewController:

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }

    //your code goes here

    return cell;
}

#endif
#endif

Поскольку контроллеры Static Table View являются хрупкими и их можно легко сломать, если вы реализуете некоторые методы источника данных или deletegate - есть проверки, которые гарантируют, что этот код будет только скомпилирован и запущен на iOS 7

Он похож на стандартный динамический UITableViewController:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }
    //your code goes here       
    return cell;
}

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

Идея одинаков для обоих случаев, и для UICollectionViewCell, как это прокомментировано в этом потоке: Ошибка авторезистентности UICollectionViewCell contentView в кадре прототипа Storyboard (Xcode 6, iOS 8 SDK) при запуске только на iOS 7

Ответ 3

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

В вашем случае UIImageView имеет расстояние от 15 до верхней части, а снизу - расстояние от 0 до нижней. Если вы установите приоритет этих ограничений на 999 (вместо 1000), приложение не будет разбиваться, потому что ограничения не требуются.

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

Ответ 4

Я до сих пор не нашел хорошего решения для раскадровки... Некоторая информация также здесь: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

От чего они советуют:

self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

Я вызвал свое решение:

  • щелкните правой кнопкой мыши раскадровку
  • Открыть как → Исходный код
  • найдите строку "44" там
  • он будет похож на

.

<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
        <rect key="frame" x="0.0" y="22" width="320" height="44"/>

.

  • заменить rowHeight = "44" с rowHeight = "9999" и height = "44" с высотой = "9999"
  • щелкните правой кнопкой мыши раскадровку
  • Открыть As → Interface Builder
  • запустите приложение и проверьте вывод

Ответ 5

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

Ответ 6

Возможно, установите приоритет вида, превышающий 750, и может решить менее 1000.

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",

Ответ 7

У меня была та же проблема. Мое решение, основанное на других выше:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // initialize my stuff
        [self layoutSubviews]; // avoid debugger warnings regarding constraint conflicts
    }
    return self;
}

Бест, Alessandro

Ответ 8

Я тоже столкнулся с этой проблемой, и ни одно из предложений не помогло. В моем случае у меня была ячейка выбора размера, и она содержала collectionView внутри (каждая ячейка collectionView содержала полноразмерное изображение). Теперь размер ячейки был немного больше (60), чем коллекцияView (50) и изображения внутри него (50). Из-за того, что представление collectionView имеет выравнивание нижнего уровня для ограничения супервизора со значением 10. Это случайное предупреждение, и единственный способ исправить это должен был сделать высоту ячейки такой же, как и в его коллекции.

Ответ 9

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

Ответ 10

Если он отлично работает в iOS8 и получает предупреждение в iOS7, вы можете искать исходный код раскадровки и находить правильный tableviewCell, а затем добавить атрибут rect после строки tableviewCell. Благодаря kuchumovn.

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>