Подтвердить что ты не робот

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: никогда не вызывается.

Надеюсь, ты поймешь, что я имею в виду. Если вам нужна дополнительная информация, дайте мне знать:)

4b9b3361

Ответ 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;
}

Вместо внедрения метода делегата вы можете перейти к построителю интерфейса и изменить значение на нуль правой и левой вставки.