Випуск обмежень щодо автоматичного макета на iOS7 в UITableViewCell


104

Я використовую обмеження автоматичного розміщення програмно для компонування моїх власних комірок 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властивість значення contentViewNO => це зіпсувало б всю клітинку.

44 - висота комірки за замовчуванням, але я визначив власні висоти у делеґаті подання таблиці, тому чому у contentView комірки є це обмеження? Що може спричинити це?

У iOS6 цього не відбувається, і все виглядає просто чудово як на iOS6, так і на iOS7.

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

Щоб уточнити, як я це роблю, про інтиалізацію комірок:

  • Я створюю всі свої мітки, кнопки тощо
  • Я встановив їхню translatesAutoresizingMaskIntoConstraintsвласність на НІ
  • Я додаю їх як підзагляд contentViewкомірки
  • Я додаю обмеження на contentView

Мені також глибоко цікаво зрозуміти, чому це відбувається лише на iOS7.


Для чого встановлено вашу власну висоту комірок?
Майк Поллард

у мене встановлена ​​висота клітини на 90
Алексіс

У колеги була та сама проблема вчора, але ширина за замовчуванням становила 320 (для додатка iPad).
jrturton

Ось приклад проекту, який демонструє цю саму проблему: github.com/Alex311/TableCellWithAutoLayout Ось деякі мої спостереження щодо цього: github.com/Alex311/TableCellWithAutoLayout/commit/…
smileyborg

Я зіткнувся з тією ж помилкою, але це було тому, що я ніколи не ініціалізував зайву прототипну комірку, яку використовував, щоб знайти висоту моєї користувацької комірки.
Стів Мозер

Відповіді:


132

У мене була така проблема. Здається, що фрейм contentView не оновлюється, поки не layoutSubviewsбуде викликано, однак кадр комірки не оновлюється раніше, залишаючи рамку contentView встановленою {0, 0, 320, 44}на час, коли оцінюються обмеження.

Переглянувши contentView більш детально, виявляється, що автоматичні маски більше не встановлюються.

Встановлення функції автоматичного розміщення маски перед обмеженням поглядів може вирішити цю проблему:

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

Це робить роботу завдяки людині. Що може статися при використанні стилів редагування?
Олексій

11
@ L14M333 Дивіться код, який я опублікував у цьому коментарі тут - в основному, ви повинні просто мати змогу встановити, self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);перш ніж додати свої обмеження, які повинні вирішити проблему.
smileyborg

2
autoresizingMask не працює для мене: початкове обмеження відсутнє, але додаються 3 нові "<NSAutoresizingMaskLayoutConstraint: 0x8b79740 h = - & - v = - & - UITableViewCellContentView: 0x8b44010.height == UITableViewcallSagle" "<NSAutoresizingMaskLayoutConstraint: 0x8b7b9f0 h = - & - v = - & - UITableViewCellScrollView: 0x8b4a130.height == LibraryCell: 0x8ac19d0.height>", "<NSAutoresizingCasy - 0x8ac19d0.height>" " 0x8ac19d0 (0)]> "
катамфетамін

1
Працює і для мене, я боровся вже як годину на цьому! Дякую! <3
мокагіо

2
Після позбавлення від інших проблем із автоматичним розміщенням (iOS 7 / iOS 8) я з’ясував, що використання self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);працює так само добре, як і використання self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;. Я ставлю це updateConstraintsперед тим, як додати обмеження до перегляду вмісту.
тестування

35

Мабуть, щось не так з UITableViewCell та UICollectionViewCell на iOS 7 за допомогою iOS 8 SDK.

Ви можете оновити contentView комірки, коли клітинку повторно використовувати так:

Для статичного 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

Оскільки контролери статичного столового перегляду неміцні і їх легко можна зламати, якщо ви впровадите якісь джерела даних або методи видалення - є перевірки, які забезпечать компіляцію та запуск цього коду лише на 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


1
Це найкраща відповідь або, принаймні, найкраще рішення для мене. Моя клітина (правила автоматичного відключення) чудово працювала в iOS8 з XCode6 і чудово працювала з iOS7 і 6 з XCode 5. Я оновлюю XCode до XCode6, і він більше не працює в iOS6 і 7. Отже, дякую !!!!
xarly

Це більше не є проблемою для Xcode 6.1. Крім того, не використовуйте NSFoundationVersionNumber, перегляньте nshipster.com/swift-system-version-checking
onmyway133

1
@ onmyway133: Чому це вже не проблема в Xcode 6.1? У мене все ще виникає проблема, навіть якщо я використовую Xcode 6.1 та iOS 8.1 SDK. Проблема виникає лише на iOS 7. Зміна меж або встановлення автоматичної маски вирішує проблему. Але я використав підхід, викладений у найбільш голосованій відповіді або в коментарях до неї.
тестування

Так, це найкраща відповідь на основі мого 3-годинного гуглінгу. Інші подібні "рішення" не містять повного списку cell.contentView.autoresizingMask. Тільки цей працює для мого проекту iPad 7.1, створеного в Xcode 6.
Золотий палець

13

Оскільки клітини повторно використовуються і висота може змінюватися залежно від вмісту, я думаю, що в цілому краще було б встановити пріоритет інтервалів менше, ніж потрібно.

У вашому випадку UIImageView має відстань від 15 доверху, а вигляд знизу має відстань від 0 до низу. Якщо встановити пріоритет цих обмежень на 999 (замість 1000), додаток не вийде з ладу, оскільки обмеження не потрібні.

Після виклику методу layoutSubviews комірка матиме правильну висоту, а обмеження можна задовольнити нормально.


Ви геній! приємне та чисте рішення дякую :)
Блеккі

9

Я все ще не знайшов хорошого рішення для розкадрів ... Деякі відомості також тут: 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" і висоту = "44" на висоту = "9999"
  • клацніть правою панеллю миші правою кнопкою миші
  • Відкрити як -> Builder інтерфейсу
  • запустити додаток і перевірити вихід

Це працювало для мене. Я створив UITableViewController в табло, де одні клітини були створені з прототипу, а інші повністю в коді шляхом інстанціювання класу.
Атхарва

3

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


Дійсно, мої клітини вище розміру за замовчуванням, але як це трапляється, що розмір за замовчуванням використовується з моменту передачі представника tableview tableView: heightForRowAtIndexPath:?
Олексій

Ймовірно, клітини створюються за замовчуванням, а потім змінюються до фактичного розміру.
Вадим Єлагін

дійсно це робить цю роботу, але чому це не відбувається на iOS6 тоді?
Олексій

3
@jafar iOS 7 змінив багато речей навколо осередків перегляду таблиці. На iOS 7 зараз перегляд прокрутки (типу UITableViewCellScrollView) між клітиною подання таблиці та contentView; це, ймовірно, пояснює різницю між iOS 6 та 7 тут.
смайлик

3

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

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

2

У мене була така ж проблема. Моє рішення, засноване на інших вище:

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

Найкраще, Алессандро


2
З Документів Apple:You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.
Рікардо Санчес-Саес

Я хочу започаткувати молитву до вас. Я шукав HOURS, який намагався виправити цю проблему, і це вирішує її (а також встановлення contentView.bounds на CGRectMake (0, 0, 99999, 99999); Отже, я з повагою не погоджуюся з документами яблук, які говорять, що не називати цю функцію. Яблуко, виправляй своє лайно.
Райан Коплі

0

Я також стикався з цією проблемою, і жодна з пропозицій не допомогла. У моєму випадку у мене була комірка вибору розміру, і вона містила collectionView всередині (кожна комірка collectionView містила зображення в повному розмірі). Тепер висота розміру комірки була трохи більшою (60), ніж колекціяView (50) та зображення всередині неї (50). Через це viewView представлення має вирівнювати низ до обмеження для перегляду зі значенням 10. Це випадок мене попередження, і єдиний спосіб виправити це, щоб зробити висоту комірки такою ж, як її collectionView.


0

Я закінчився тим, що не використовую UITableViewCell в дизайнері взагалі ... Я створюю там спеціальний вигляд і додаю його до перегляду вмісту комірки програмно ... З деякими категоріями довідки також немає кодової таблички коду ...


0

Якщо він добре працює в 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"/>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.