Проблема автосохранения календаря содержимого UICollectionViewCell в ячейке прототипа Storyboard (Xcode 6, iOS 8 SDK) происходит при запуске только на iOS 7

Я использую Xcode 6 Beta 3, iOS 8 SDK. Создайте целевой iOS 7.0 с помощью Swift. Пожалуйста, обратитесь к моей проблеме шаг за шагом со скриншотами ниже.

У меня есть UICollectionView в раскадровке. 1 Prototype UICollectionViewCell, который содержит 1 ярлык в центре (без правила автореализации). Фиолетовый фон состоял в том, чтобы отметить contentView, который создается во время выполнения Cell. В конечном итоге это представление будет правильно изменено на моем 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

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]
}

Ответ 2

Я столкнулся с той же проблемой и попросил Apple DTS получить помощь. Их ответ был:

В iOS 7 просмотры содержимого ячеек сами по себе определяют путем авторезистирования маски. В iOS 8 это было изменено, ячейки перестали использовать авторезистировать маски и начать определение содержимого в layoutSubviews. Если нить кодируется в iOS 8, а затем декодирует его на iOS 7, у вас будет просмотр содержимого без маски авторезистации и нет другие средства, с помощью которых можно самим определять размер. Поэтому, если вы когда-либо меняете рамку ячейки, представление содержимого не будет следовать.

Приложения, развертывающие обратно в iOS 7, должны будут обойти это определение размера содержимого, добавление авторезистирующих масок или добавление ограничения.

Я предполагаю, что это означает, что это не ошибка в XCode 6, а несовместимость между iOS 8 SDK и iOS 7 SDK, которая поразит вас, если вы перейдете на Xcode 6, потому что он автоматически начнет использовать iOS 8 SDK.

Как я уже говорил, обходной путь Даниэля Пламана описан для меня. Те, о которых рассказывают Игорь Палагута и KoCMoHaBTa, выглядят более просто и, похоже, имеют смысл дать ответ Apple DTS, поэтому я попробую их позже.

Ответ 3

Я столкнулся с той же проблемой и надеюсь, что Apple исправит это со следующей версией Xcode. Тем временем я использую обходной путь. В моем подклассе UICollectionViewCell я только что переопределил layoutSubviews и изменил размер содержимогоView вручную, если размер отличается от размера 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;
  }
}

Ответ 4

Другим решением является установка размера contentView и масок авторазрешения в -collectionView: cellForItemAtIndexPath: например:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
     static NSString *cellID = @"CellID";

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

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

     //You custom code goes here

     return cell;
}

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

Ответ 5

В 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)]];

Ответ 6

Это не будет работать корректно без каких-либо других упомянутых обходных решений из-за ошибки в Xcode 6 GM с тем, как Xcode компилирует xib файлы в формат nib. Хотя я не могу сказать на 100% уверенность, что это связано с Xcode и не связано со временем выполнения, я очень уверен в этом: вот как я могу это показать:

  • Сборка + Запуск приложения в Xcode 5.1.
  • Перейдите в каталог приложения simulator и скопируйте скомпилированный .nib файл для xib, с которым у вас возникли проблемы.
  • Build + Запустите приложение в Xcode 6 GM.
  • Остановить приложение.
  • Замените файл .nib во вновь созданной папке симулятора приложения с файлом .nib, созданным с помощью Xcode 5.1
  • Перезапустите приложение из симулятора, а не с Xcode.
  • Ваша ячейка, загруженная из этого .nib, должна работать как ожидалось.

Я надеюсь, что каждый, кто прочитает этот вопрос, подаст радар с Apple. Это ОГРОМНАЯ проблема и требует решения перед окончательной версией Xcode.

Изменить: В свете ecotax post, я просто хотел обновить это, чтобы сказать, что теперь подтверждены различия в поведении между зданием в iOS 8 и iOS 7, но не Жук. Мой взлом исправил проблему, потому что построение на iOS 7 добавило маску авторезистирования в представление контента, необходимое для выполнения этой работы, которое Apple больше не добавляет.

Ответ 7

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

Во-первых, существует два "правила":

  • Для представлений, созданных программно (пример [UIView new]), для свойства translatesAutoresizingMaskIntoConstraints установлено значение YES
  • Представления, созданные в конструкторе интерфейса, с включенным автозапуском, будут иметь свойство translatesAutoresizingMaskIntoConstraints, установленное в NO

Второе правило, похоже, не относится к представлениям верхнего уровня, для которых вы не определяете ограничения. (Пример содержимого)

При просмотре ячейки раскадровки обратите внимание на то, что у ячейки нет ее 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"/>

Итак, есть два вывода:

  • contentView translatesAutoresizingMaskIntoConstraints установлен на YES.
  • contentView отсутствует определение макета.

Это приводит нас к двум решениям, о которых говорили.

Маски авторезистировки можно настроить вручную в awakeFromNib:

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

Или вы можете установить contentView translatesAutoresizingMaskIntoConstraints в NO в awakeFromNib и определить ограничения в - (void)updateConstraints.

Ответ 8

Это сводная версия ответа @Igor, которая принимается и благодарит за ваш приятный ответ.

Сначала Перейдите к подклассу 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, которое работает безупречно.

Спасибо, надеюсь, это помогло.

Ответ 9

В swift поместите следующий код в подкласс ячейки представления коллекции:

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

Ответ 10

Я обнаружил, что есть проблемы с размером 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
}

Этот метод следует вызывать после удаления ячейки.

Ответ 11

Я исправил это:

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

см. здесь

Ответ 12

Просто убедитесь, что вы установите флажок "Autoresize subviews" в nib для этой ячейки представления коллекции. Он отлично работает как на iOS 8, так и на iOS 7.