UICollectionViewFlowLayout не отменяет права на изменение ориентации
У меня есть UICollectionView с UICollectionViewFlowLayout. Я также реализую протокол UICollectionViewDelegateFlowLayout.
В моем источнике данных у меня есть куча UIViewControllers, которые отвечают на собственный протокол, поэтому я могу запросить их размер и некоторые другие вещи.
В делегате FlowLayout, когда он запрашивает sizeForItemAtIndexPath:, я возвращаю размер элемента, который я получаю из своего протокола. ViewControllers, которые реализуют мой протокол, возвращают другой размер элемента в зависимости от ориентации.
Теперь, если я изменяю ориентацию устройства с портрета на пейзаж, нет проблем (элементы больше в ландшафте), но если я изменю его, я получу это предупреждение:
the item width must be less that the width of the UICollectionView minus the section insets left and right values.
Please check the values return by the delegate.
Он по-прежнему работает, но мне не нравится получать предупреждения, поэтому, возможно, вы можете сказать мне, что я делаю неправильно. Также есть еще одна проблема. Если я не укажу, что collectionViews коллекции collectionViewLayout недействителен в willAnimateRotationToInterfaceOrientation: sizeForItemAtIndexPath: никогда не вызывается.
Надеюсь, ты поймешь, что я имею в виду. Если вам нужна дополнительная информация, дайте мне знать:)
Ответы
Ответ 1
Одним из решений является использование KVO и прослушивание изменений в рамке супервизора для вашего вида коллекции. Calling -reloadData будет работать и избавиться от предупреждений. Здесь есть основная проблема синхронизации...
// -loadView
[self.view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
// -dealloc
[self.view removeObserver:self forKeyPath:@"frame"];
// KVO Method
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[collectionView_ reloadData];
}
Ответ 2
Этот ответ задерживается, но принятый ответ не сработал у меня. Я сочувствую OP в том, что я хочу угадать и забыть UICollectionViewFlowLayout. Я предлагаю, чтобы недействительность макета в контроллере представления на самом деле была лучшим решением.
Мне нужна была одна горизонтальная линия прокрутки ячеек, сосредоточенная в представлении, как в портретной, так и в альбомной ориентации.
Я подклассифицировал UICollectionViewFlowLayout.
Я переделал makeLayout, чтобы пересчитать вставки, а затем вызовет [super prepareLayout].
Я перепробовал getter для collectionViewContentSize, чтобы убедиться, что размер содержимого верен.
Макет не сделал недействительным сам по себе, даже если границы менялись с переориентацией.
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// does the superclass do anything at this point?
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
// do whatever else you need before rotating toInterfaceOrientation
// tell the layout to recalculate
[self.collectionViewLayout invalidateLayout];
}
UICollectionViewFlowLayout поддерживает положение прокрутки между ориентациями. Одна и та же ячейка будет центрирована только в том случае, если она квадратная.
Ответ 3
Я использовал комбинацию двух ответов здесь, чтобы сделать то, что мы все пытаемся сделать, действительно, сделать просмотр коллекции похожим на представление таблицы, но не использовать UITableView и получать элементы в одном столбце (скорее всего)
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self.collectionView.collectionViewLayout invalidateLayout];
}
Ответ 4
Вариант ответа @meelawsh, но в Swift и без свойства self.sizeForCollectionView
:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
guard let collectionView = self.collectionView else {
return
}
if size.width > collectionView.frame.width {
// bigger
let animation: (UIViewControllerTransitionCoordinatorContext)->(Void) = {
context in
collectionView.collectionViewLayout.invalidateLayout()
}
coordinator.animateAlongsideTransition(animation, completion: nil)
} else {
// smaller
collectionView.collectionViewLayout.invalidateLayout()
}
}
Ответ 5
Я не знаю, может ли он помочь кому-то, но ни один из последних ответов не поможет мне, потому что я использую UIViews
в UIScrollView
.
Я запускаю UIViews программно в зависимости от некоторых событий. Поэтому я не могу использовать - (void) willRotateToInterfaceOrientation:
и invalidateLayout
или reloadData
, потому что:
1. invalidateLayout "происходит во время следующего цикла обновления макета представления."
2. reloadData "Для эффективности в представлении коллекции отображаются только те ячейки и дополнительные виды, которые видны".
Для меня работала ширина родительского элемента collectionView (UIView):
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
int currentWidth = self.frame.size.width;
UIEdgeInsets sectionInset = [(UICollectionViewFlowLayout *)collectionView.collectionViewLayout sectionInset];
int fixedWidth = currentWidth - (sectionInset.left + sectionInset.right);
По какой-то причине кадр collectionView имел ширину портрета в то время, чтобы вызвать эту функцию... используя int currentWidth = self.frame.width
, помогите мне исправить это.
Ответ 6
iOS8: единственный способ заставить замолчать предупреждение - вызвать недействительность во время перехода при повороте в больший размер и до перехода при повороте на меньший размер.
self.sizeForCollectionView = size; //used to determine collectionview size in sizeForItem
if (size.width <= size.height) {
[self.collectionView.collectionViewLayout invalidateLayout];
}
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (size.width > size.height) {
[self.collectionView.collectionViewLayout invalidateLayout];
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
}];
Ответ 7
Ответ @0mahc0 работал у меня, но только частично.
У меня нет проблемы с поворотом, потому что я принудительно подключаю приложение только в режиме Portrait, но мое решение может помочь другим с той же проблемой.
Предупреждение отображается каждый раз, когда отображается представление. Причина предупреждения очень ясна, мы определили секционные вставки слева и справа от UICollectionView. Проверьте построитель интерфейсов, и вы увидите в показателях те значения, которые определены.
Решение @0mahc0 работает, но я хочу растянуть ячейку до максимальной ширины, поэтому я удалил вставки раздела, иначе у меня будет "margin" слева и справа.
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
return UIEdgeInsetsZero;
}
Вместо внедрения метода делегата вы можете перейти к построителю интерфейса и изменить значение на нуль правой и левой вставки.