Автоматизація випуску кадру UICollectionViewCell contentView у комірці прототипу Storyboard (Xcode 6, iOS 8 SDK) відбувається під час роботи лише на iOS 7


158

Я використовую Xcode 6 Beta 3, iOS 8 SDK. Збірка Target iOS 7.0 за допомогою Swift. Будь ласка, зверніться до моєї проблеми крок за кроком із скріншотами нижче.

У мене є UICollectionView в аркуші розказок. 1 прототип UICollectionViewCell, який містить 1 мітку в центрі (немає правила автоматичного розміщення). Фіолетовий фон повинен був позначити contentView, який генерується під час виконання клітиною, я думаю. Цей погляд буде змінено належним чином на базі мого UICollectionViewLayoutDelegate з часом, але не на iOS 7. Зауважте, що я використовую Xcode 6, і проблема трапляється лише на iOS 7.

Коли я будую додаток на iOS 8. Все гаразд.

Примітка: Фіолетовий - це contentView , синій - мій UIButton із закругленим кутом.

http://i.stack.imgur.com/uDNDY.png

Однак на iOS 7 всі підвиди внутрішнього осередку раптово скорочуються до рамки (0,0,50,50) і більше ніколи не відповідають моїм правилам автоматичної автоматизації.

http://i.stack.imgur.com/lOZH9.png

Я припускаю, що це помилка в iOS 8 SDK або Swift чи, можливо, Xcode?


Оновлення 1: Ця проблема все ще існує в офіційному Xcode 6.0.1! Найкраща робота - це те, що запропонував KoCMoHaBTa нижче, встановивши кадр у cellForItem клітинки (Хоча ви маєте підклас своєї комірки). Виявилося, що це несумісність між iOS 8 SDK та iOS 7 (перевірте відповідь екотакси нижче, цитовану з Apple).

Оновлення 2: Вставте цей код на початку свого CellForItem, і все повинно бути добре:

/** Xcode 6 on iOS 7 hot fix **/
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
/** End of Xcode 6 on iOS 7 hot fix **/

1
Я дізнався, що ця проблема все ще існує в Xcode 6 Beta 5. Хтось теж відчував це?
квітня

2
Я боюся з цим зараз у своєму проекті. iOS 7 та iOS 8, побудовані за допомогою Xcode 5, виглядають чудово. iOS 8, побудований за допомогою Xcode 6 beta 6, виглядає чудово. iOS 7, побудований за допомогою Xcode 6 beta 6, має проблему, яку ви описуєте. Використовуючи Reveal, я можу побачити, що мій UICollectionViewCell має відповідний розмір. Але зміст огляду вмісту комірки не було змінено, навіть незважаючи на те, що він є батьківським. Розмір contentView встановлюється у тому, що має аркуш розповідей. Я не використовую авторозкладку в цьому проекті. Мій проект повністю об'єктивний-c.
Дель Браун

2
Я просто хотів додати, що ця проблема все ще існує як насіння Xcode 6 / iOS 8 GM. @ Відповідь ДаніелаПламана примусити contentViewзмінити розмір клітинки добре працює, щоб вирішити проблему. Я здогадуюсь, що в iOS 8 Apple щось змінила щодо того, як обробляються погляди на вміст комірок, коли вони створюються в Interface Builder (що все одно є трохи чорною скринькою). Але той факт, що він змінює поведінку під час націлювання на iOS 7, безумовно, помилка.
Стюарт

Те саме тут з Xcode 6 GM, автоматичним макетом та осередком на основі нитки. Я фіксую це, приклеюючи contentViewкраї до країв комірки.
sergiou87

3
Я завантажив xcode 6.1, але все ще бачу ту саму проблему в тренажері.
Хайтао Лі

Відповіді:


169

contentView порушено. Його також можна зафіксувати в awakeFromNib

ObjC:

- (void)awakeFromNib {

    [super awakeFromNib];

    self.contentView.frame = self.bounds;
    self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}

Swift3:

override func awakeFromNib() {
    super.awakeFromNib()

    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}

3
Зробив фокус без self.contentView.frame = self.bounds; Думаєте, мені це потрібно? Все одно, дякую!
Міхал Шац

Привіт Міхал, погоджуюся з тобою. Але на 100%, щоб бути впевненим, як це буде працювати в наступних iOS, краще додати це, я думаю.
Ігор Палагута

5
Мені подобається ця відповідь, але вам потрібно зателефонувати [super awakeFromNib]; Також я замислююся над тим, щоб додати чек на iOS 7.1 і менше, тому що я не впевнений, як додавання цих масок зміни розміру впливає на поведінку за замовчуванням на iOS8.
GingerBreadMane

Якщо ви не користуєтеся нибами або дошками розкадрів, це також працює, якщо ви помістите його у applyLayoutAttributes:
cetcet

Це не працює для мене. Я не використовую Autolayout !! Будь-яка допомога?
thatzprem

61

Я зіткнувся з тією ж проблемою і попросив Apple DTS про допомогу. Їх відповідь:

В iOS 7 перегляд вмісту комірок розміру розмірів за допомогою автоматичних масок. В iOS 8 це було змінено, осередки перестали використовувати автоматичні маски і почали розміщувати перегляд вмісту в layoutSubviews. Якщо ниб зашифровано в iOS 8, а потім розшифрує його на iOS 7, у вас буде перегляд вмісту без автоматичної маски та інших засобів, за допомогою яких можна розмістити розмір. Тож якщо ви коли-небудь зміните рамку комірки, перегляд вмісту не буде дотримуватися.

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

Я думаю, це означає, що це не помилка в XCode 6, а несумісність між iOS 8 SDK та iOS 7 SDK, яка вразить вас, якщо ви оновите до Xcode 6, оскільки він автоматично почне використовувати SDK iOS 8.

Як я коментував раніше, обхідний метод Даніель Пламан описав твори для мене. Описані Ігорем Палагутою та KoCMoHaBTa виглядають простішими, але, здається, має сенс дати відповідь Apple DTS, тому я спробую їх пізніше.


Це цікаво, але я все ще сподіваюся, що вони це виправлять. Така поведінка була введена лише в Xcode 6 GM, який додав підтримку iPhone 6. Він працював чудово у попередніх бетах. Я навіть повернув проект до попередньої бета-версії після того, як я його помітив, і він працював так, як очікувалося. Я сподіваюся, що всі надсилають помилки в Apple з цього питання.
Артон

@arton Я подав повідомлення про помилку того ж дня, коли я попросив DTS про допомогу. Він був закритий як дублікат 18312246. Не впевнений, наскільки це допомагає.
екотакс

Я використав обхід, розміривши ContentView і працює для мене. - (CGSize) collectionViewContentSize {повернути CGSizeMake (self.collectionView.bounds.size.width, self.collectionView.bounds.size.height); }
Хесус Хуртадо

60

Я зіткнувся з тією ж проблемою і сподіваюся, що Apple виправить це з наступною версією Xcode. Тим часом я використовую спосіб вирішення. У своєму UICollectionViewCellпідкласі я щойно layoutSubviewsзмінив і змінив розмір contentView вручну, якщо розмір відрізняється від collectionViewCellрозміру.

- (void)layoutSubviews
{
  [super layoutSubviews];

  BOOL contentViewIsAutoresized = CGSizeEqualToSize(self.frame.size, self.contentView.frame.size);

  if( !contentViewIsAutoresized) {
    CGRect contentViewFrame = self.contentView.frame;
    contentViewFrame.size = self.frame.size;
    self.contentView.frame = contentViewFrame;
  }
}

Так, я використовував подібну роботу, але я це робив у cellForItem / cellForRow, який також працює.
помер

1
Це найкраще рішення. Додавання цього в cellForItem / cellForRow призведе до дивних артефактів, якщо ви обертаєте пристрій і змінюється розмір комірки.
шпигун

Привіт! У мене виникла проблема з цим кодом. Вперше булевий contentViewIsAutoresized буде істинним, якщо він завантажений із комірки розкадрів чи комірки-прототипу. Тільки коли ви зробите reloadData, друге це буде правильно. Тому вам не потрібно перевіряти розмір. Натомість просто робіть: self.contentView.frame = self.bounds;
помер

Підтверджено: ми повинні робити це у cellForItem або cellForRow, оскільки layoutSubviews викликається лише після повернення комірки. Все, що ви робите до цього, як малювання матеріалів, буде неправильно обчислено.
помер

1
Гм, може, краще розмістити [cell layoutIfNeeded];в cellForItem або cellForRow?
wtorsi

38

Іншим рішенням є встановлення розміру contentView і автоматичних масок, -collectionView:cellForItemAtIndexPath:як описано нижче:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

     static NSString *cellID = @"CellID";

     UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

     // Set contentView's frame and autoresizingMask
     cell.contentView.frame = cell.bounds;
     cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;

     // Your custom code goes here

     return cell;
}

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


2
Це чудове рішення, оскільки воно працює з будь-яким типом комірок без підкласифікації і не вимагає змін у декількох місцях, коли ви використовуєте більше одного типу комірок у вікні колекції.
nacross

6

У Xcode 6.0.1 contentView для UICollectionViewCell розбито для пристроїв iOS7. Його можна також виправити, додавши належні обмеження до UICollectionViewCell та його contentView методами awakeFromNib або init.

        UIView *cellContentView = self.contentView;
        cellContentView.translatesAutoresizingMaskIntoConstraints = NO;

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];

Тільки це працює зараз, ви повинні це зробити тільки для IOS 8, і я повинен викликати це після кожного декею! Але це також не є ідеальним рішенням, оскільки багаторазовий вибір не працює так, як повинен бути візуально ...
Renetik

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

Маска для мене не працює; однак встановлення обмежень працює!
entropid

4

Це не спрацює правильно без жодного з інших згаданих вирішень через помилку в Xcode 6 GM з тим, як Xcode збирає файли xib у формат nib. Хоча я не можу сказати на 100% впевненість, що це пов'язано з Xcode і не пов'язане з виконанням часу, я дуже впевнений - ось як я це можу показати:

  1. Build + Запуск програми в Xcode 5.1.
  2. Перейдіть до каталогу програми симулятора та скопіюйте скомпільований .nib файл для xib, у якого виникають проблеми.
  3. Build + Запуск програми в Xcode 6 GM.
  4. Зупиніть програму.
  5. Замініть файл .nib у папці симулятора щойно створеної програми на файл .nib, створений за допомогою Xcode 5.1
  6. Перезапустіть додаток із симулятора, а не з Xcode.
  7. Ваша комірка, завантажена з цього .nib, повинна працювати як очікувалося.

Я сподіваюся, що кожен, хто прочитає це питання, подасть Радар з Apple. Це ВЕЛИЧЕЗНА проблема та потребує вирішення перед остаточним випуском Xcode.

Редагувати: У світлі публікації про екотакси , я просто хотів оновити це, щоб сказати, що зараз підтверджено відмінності в поведінці між побудовою в iOS 8 проти iOS 7, але не помилка. Мій хак вирішив проблему, оскільки побудова на iOS 7 додала маску для автоматичного додавання до перегляду вмісту, необхідного для роботи, чого Apple більше не додає.


Я не впевнений, чи законно вони можуть випустити інший xCode, ніж версія GM
Mabedan

Ха-ха, вони підуть до в'язниці? = P Але з усією серйозністю, впевнені, що можуть. У них було кілька версій GM для Mavericks, якщо ви не пам’ятаєте. Це не надто часто, але може статися.
Ейсі

4

Відповіді в цій публікації, що я ніколи не зрозумів, чому це працює.

По-перше, є два "правила":

  1. Для представлень, створених програмно (напр. [UIView new]), Властивість translatesAutoresizingMaskIntoConstraintsвстановлено уYES
  2. Види створені в інтерфейсі будівельника, з підтримкою AutoLayout, матиме властивість translatesAutoresizingMaskIntoConstraintsнабору вNO

Друге правило, схоже, не стосується представлень верхнього рівня, для яких ви не визначаєте обмежень. (Наприклад, перегляд вмісту)

Дивлячись на клітинку Storyboard, зауважте, що комірка не contentViewпіддається впливу. Ми не "контролюємо" contentView, Apple є.

Заглибтеся у вихідний код розповіді та подивіться, як contentViewвизначається комірка:

<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">

Тепер підпогляди комірки (зауважте translatesAutoresizingMaskIntoConstraints="NO"):

<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NaT-qJ-npL" userLabel="myCustomLabel">

У contentViewнього не translatesAutoresizingMaskIntoConstraintsвстановлено NO. Крім того, йому не вистачає визначення верстки, можливо, через те, що сказав @ecotax .

Якщо ми подивимось на це contentView, у нього є автоматизована маска, але для неї немає визначення: <autoresizingMask key="autoresizingMask"/>

Отже, є два висновки:

  1. contentView translatesAutoresizingMaskIntoConstraintsвстановлено на YES.
  2. contentView відсутнє визначення макета.

Це призводить нас до двох рішень, про які вже йшлося.

Ви можете встановити автоматичні маски вручну awakeFromNib:

self.contentView.frame = cell.bounds;
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Або ви можете встановити , contentView translatesAutoresizingMaskIntoConstraintsщоб NOв awakeFromNibі визначення обмежень в - (void)updateConstraints.


4

Це швидка версія відповіді @ Ігоря, яка прийнята і дякує за вашу чудову відповідь.

Спочатку перейдіть до свого UICollectionViewCellпідкласу та вставте наступний код таким, який він знаходиться всередині класу.

override func awakeFromNib() {
    super.awakeFromNib()
    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
}

До речі, я використовую Xcode 7.3.1 та Swift 2.3. Рішення тестується на iOS 9.3, який працює бездоганно.

Дякую, сподіваюся, що це допомогло.


Вибачте за мою погану англійську, я мав на увазі "працює як шарм" :)
Aznix

@Aznix Немає питання .. :)
onCompletion

2

Швидко розмістіть у підкласі комірок подання колекції такий код:

override var bounds: CGRect {
  didSet {
    // Fix autolayout constraints broken in Xcode 6 GM + iOS 7.1
    self.contentView.frame = bounds
  }
}

Це була відповідь, яку я шукав. Я вирішував цю проблему (я не знав, як записати її в Swift), переосмислюючи setBounds в Objective-C. Дякую :)
Меттью Каулі

1

Я виявив, що також є проблеми із contentViewрозміром в iOS 8. Це, як правило, викладається дуже пізно в циклі, що може спричинити тимчасові конфлікти обмежень. Щоб вирішити це питання, я додав наступний метод у категорію UICollectionViewCell:

- (void)fixupContentView
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 80100
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) {
        self.contentView.frame = self.bounds;
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    } else {
        [self layoutIfNeeded];
    }
#endif
#endif
}

Цей метод слід викликати після відміни клітини.


Ідеально було б, якби цей метод викликався автоматично. Мені це не подобається, але це можна зробити за допомогою шипування dequeueReusableCellWithReuseIdentifier:forIndexPath:.
phatmann

Здається, Apple виправила цю проблему у версії 8.1 SDK для iOS у Xcode 6.1 GM (Build 6A1042b). Тому я оновив код вище, щоб він не запускався при використанні 8.1 SDK. Після того, як ваша команда перейшла на Xcode 6.1, ви можете повністю видалити цей злом.
phatmann

1

Я вирішив це зробити:

override func layoutSubviews() {
   contentView.superview?.frame = bounds
   super.layoutSubviews()
}

див .: тут


-1

Просто переконайтесь, що ви встановите прапорець "Автоматизувати розмір підвидів" у вікні цієї комірки подання колекції. Він буде добре працювати як на iOS 8, так і на iOS 7.


Ні, це не так. Це вбудована комірка прототипу.
помер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.