16

2015-08-18 16: 07: 51,523 Пример [16070: 269647] поведение UICollectionViewFlowLayout не определен, так как: 2015-08-18 16: 07: 51.523
Пример [16070: 269647] ширина элемента должна быть меньше Ширина UICollectionView минус вставки вставки слева и значения правого знака, минус вставки содержимого слева и справа ,
2015-08-18 16: 07: 51.524 Пример [16070: 269647] Соответствующий экземпляр UICollectionViewFlowLayout, и он присоединен к; анимация = { position =; bounds.origin =; bounds.size =; }; layer =; contentOffset: {0, 0}; contentSize: {1024, 770}> коллекция вид расположение:. 2015-08-18 16: 07: 51.524 Пример [16070: 269647] Сделайте символическую точку останова на UICollectionViewFlowLayoutBreakForInvalidSizes, чтобы поймать это в отладчике.поведение UICollectionViewFlowLayout не определен, так как ширина ячейки больше, чем ширина CollectionView

Это то, что я получаю, что я делаю

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 
     return CGSizeMake(self.collectionView!.frame.size.width - 20, 66) 
    } 

, когда я поворачиваю от пейзажа до портрета, консоль показывает сообщение об ошибке только в прошивке 9, кто-нибудь знает, что это происходит, и если есть ли исправление для этого?

Screenshot

+0

Решена ли проблема? –

+0

nope, его не разрешено –

ответ

0

У меня была аналогичная проблема.

В моем случае у меня был вид коллекции, и когда вы постучали по одной из ячеек, открылся popover с UITextField, чтобы отредактировать элемент. После этого popover исчез, self.collectionView.contentInset.bottom был установлен в 55 (изначально 0).

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

contextual prediction bar

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

Поскольку ваша проблема, похоже, связана с шириной, а не с высотой ячейки, проверьте, не соответствуют ли какие-либо из значений contentInset или layout.sectionInset тем, которые были установлены вами.

7

Это происходит потому, что ширина ячейки коллекции больше, чем ширина просмотра коллекции после вращения. Предположим, что у вас есть экран 1024x768, и ваш вид коллекции заполняет экран. Когда ваше устройство является ландшафтом, ширина вашей ячейки будет self.collectionView .frame.size.width - 20 = 1004 и его ширина больше, чем ширина коллекции в портрете = 768. Отладчик говорит, что «ширина элемента должна быть меньше ширины UICollectionView за вычетом значений вставки слева и справа, минус вставки содержимого влево и вправо ".

+0

Правильно ... так как вы его исправите ... – Magoo

+0

@Magoo Вы можете исправить это, изменив значения макета потока представления коллекции для размера элемента. Делегат должен рассмотреть вопрос о ротации. Как говорит отладчик, ширина элемента должна быть меньше ширины UICollectionView минус значения вставки левого и правого секций, минус значения вставки вставки слева и справа. – mohammadrhemmati

4

Я использую подкласс UICollectionViewFlowLayout и используя его свойство itemSize, чтобы указать размер ячейки (вместо метода делегата collectionView:sizeForItemAtIndexPath:). Каждый раз, когда я поворачиваю экран на более короткую ширину (например, пейзаж -> портрет), я получаю это огромное предупреждение.

Я смог исправить это, выполнив 2 шага.

Шаг 1: В UICollectionViewFlowLayoutprepareLayout() функции подкласса, отойдите super.prepareLayout() к после где self.itemSize установлен. Я думаю, что это делает суперкласс использовать правильное значение itemSize.

import UIKit 

extension UICollectionViewFlowLayout { 

    var collectionViewWidthWithoutInsets: CGFloat { 
    get { 
     guard let collectionView = self.collectionView else { return 0 } 
     let collectionViewSize = collectionView.bounds.size 
     let widthWithoutInsets = collectionViewSize.width 
     - self.sectionInset.left - self.sectionInset.right 
     - collectionView.contentInset.left - collectionView.contentInset.right 
     return widthWithoutInsets 
    } 
    } 

} 

class StickyHeaderCollectionViewLayout: UICollectionViewFlowLayout { 

    // MARK: - Variables 
    let cellAspectRatio: CGFloat = 3/1 

    // MARK: - Layout 
    override func prepareLayout() { 
    self.scrollDirection = .Vertical 
    self.minimumInteritemSpacing = 1 
    self.minimumLineSpacing = 1 
    self.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: self.minimumLineSpacing, right: 0) 
    let collectionViewWidth = self.collectionView?.bounds.size.width ?? 0 
    self.headerReferenceSize = CGSize(width: collectionViewWidth, height: 40) 

    // cell size 
    let itemWidth = collectionViewWidthWithoutInsets 
    self.itemSize = CGSize(width: itemWidth, height: itemWidth/cellAspectRatio) 

    // Note: call super last if we set itemSize 
    super.prepareLayout() 
    } 

    // ... 

} 

Обратите внимание, что приведенное выше изменение каким-то образом изменит размер макета, когда экран вращается, перестает работать. Это где шаг 2 приходит в

Шаг 2:. Поместите это в контроллеревида, который содержит представление коллекции.

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 
    collectionView.collectionViewLayout.invalidateLayout() 
    } 

Теперь предупреждение исчезает :)

+1

плохо смотрю на это решение, ответ пришел намного позже, чем я вышел из проекта :( –

12

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

Почему ячейка становится слишком большой, так как необходимо отобразить макет потока представления коллекции и вернуть подходящий размер?

CollectionView (CollectionView: UICollectionView, расположение collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath)

Обновление включает Swift 4

@objc переопределение FUNC CollectionView (_ CollectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {...}

Это потому, что эта функция не называется или, по крайней мере, не сразу.

Что происходит, так это то, что подкласс класса представления представления коллекции не переопределяет функцию shouldInvalidateLayoutForBoundsChange, которая по умолчанию равна returns false.

Когда этот метод возвращает значение false, сначала открывается представление коллекции с текущим размером ячейки, обнаруживает проблему (которая регистрирует предупреждение), а затем вызывает макет потока для изменения размера ячейки.

Это означает 2 вещи:

1 - предупреждение само по себе не является вредным

2 - вы можете избавиться от него, просто перекрывая функцию shouldInvalidateLayoutForBoundsChange вернуть истинный. В этом случае раскладка потока всегда будет вызываться при изменении границ представления коллекции.

+0

Я пробовал все возможные предложения в Интернете, и этот правильный ответ !!! Большое спасибо за подробное объяснение и простое решение! Если бы я мог бы ответить на этот ответ 10 раз. – ElectroBuddha

+0

Спасибо, это сработало для меня. UPDATE for swift 4: измените «sizeForItemAtIndexPath» на «sizeForItem», иначе он НЕ будет работать и НЕ покажет никаких ошибок. –

3

Вы можете проверить отладчик, если collectionView.contentOffset изменен на отрицательный, в моем случае он изменяется с (0,0) на (0,-40).Вы можете решить эту проблему с помощью этого метода

if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) { 
    self.automaticallyAdjustsScrollViewInsets = NO; 
} 
2

После выполнения некоторых экспериментировал, это, кажется, также связаны с тем, как вы макет вашего CollectionView.

Tl; dr: Используйте AutoLayout, а не autoresizingMask.

Так что для ядра проблемы лучшие решения я нашел, чтобы справиться с изменением ориентации используйте следующий код, который все это имеет смысл:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransition(to: size, with: coordinator) 

    coordinator.animate(alongsideTransition: { (context) in 
     self.collectionView.collectionViewLayout.invalidateLayout() 
    }, completion: nil) 
} 

Однако, есть еще ситуации, в которых вы можете получите предупреждение о размере элемента. Для меня это, если я нахожусь в ландшафте на одной вкладке, переключитесь на другую вкладку, поверните на портрет и вернитесь к предыдущей вкладке. Я попытался сделать недействительным макет в willAppear, willLayout, всех обычных подозреваемых, но не повезло. На самом деле, даже если вы звоните invalidateLayoutдоsuper.willAppear() вы все еще получаете предупреждение.

И в конечном итоге эта проблема связана с размером обновления границ коллекции, прежде чем делегат попросит элемент itemize.

Так что с учетом этого я попытался использовать AutoLayout вместо collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight], и с этим проблема решена! (Я использую SnapKit, чтобы делать AutoLayout, чтобы я не вытаскивал свои волосы постоянно). Вам также просто нужно invalidateLayout в viewWillTransition (без coordinator.animate, так же, как у вас в вашем примере), а также invalidateLayout внизу viewWillAppear(:). То, что кажется для покрытия всех ситуаций.

Я не знаю, пользуетесь ли вы авторезистированием или нет - было бы интересно узнать, работает ли моя теория/решение для всех.

1

У меня была та же проблема. Я исправил это, очистив мой просмотр коллекции своих ограничений и сбросив их в Storyboard.

-1

Это то, что вам нужно:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
    //Get frame width 
    let width = self.view.frame.width 
    //I want a width of 418 and height of 274 (Aspect ratio 209:137) with a margin of 24 on each side of the cell (See insetForSectionAt 24 + 24 = 48). So, check if a have that much screen real estate. 
    if width > (418 + 48) { 
     //If I do return the size I want 
     return CGSize(width: 418, height: 274) 
    }else{ 
     //Get new width. Frame width minus the margins I want to maintain 
     let newWidth = (width - 48) 
     //If not calculate the new height that maintains the aspect ratio I want. NewHeight = (originalHeight/originalWidth) * newWidth 
     let height = (274/418) * newWidth 
     //Return the new size that is Aspect ratio 209:137 
     return CGSize(width: newWidth, height: height) 
    } 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 
    return UIEdgeInsets(top: 24, left: 24, bottom: 24, right: 24) 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 
    return 33 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 
    return 33 
} 
1

Я решить эту проблему с помощью safeAreaLayoutGuide.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 

    return CGSize(width: (view.safeAreaLayoutGuide.layoutFrame.width), height: 80); 
} 

, и вы также должны переопределить эту функцию для правильной поддержки портретного и ландшафтного режима.

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    collectionView?.collectionViewLayout.invalidateLayout(); 
}