2016-05-21 2 views
6

Я реализую представление коллекции, элементы которого имеют размер, основанный на границах вида коллекции. Поэтому, когда размер изменяется, из-за поворота устройства, например, мне нужно сделать недействительным макет, чтобы размеры ячеек были изменены, чтобы рассмотреть новые границы просмотра коллекции. Я сделал это через API viewWillTransitionToSize.Правильный способ недействительности макета коллекции при изменении размера

Это хорошо работает, пока пользователь не представляет собой контроллер модального представления над контроллером представления, который содержит представление коллекции, поворачивает устройство, а затем отклоняет его. При этом размер элемента не обновляется до соответствующего размера. Вызывается viewWillTransitionToSize, и макет считается недействительным, как и ожидалось, но границы представления коллекции по-прежнему являются старым значением. Например, при повороте от портрета к пейзажу значение ограничения просмотра коллекции все еще имеет высоту, большую, чем ширина. Я не уверен, почему так, но мне интересно, если это лучший способ аннулировать при изменении размера? Есть ли лучший способ сделать это?

Я также попытался подклассов UICollectionViewFlowLayout и первостепенную shouldInvalidateLayoutForBoundsChange вернуться YES, но по каким-то причинам это не работает, даже вращающаяся без модальных презентации. Он также не использует правильные рамки просмотра коллекции.

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(nonnull id<UIViewControllerTransitionCoordinator>)coordinator 
{ 
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; 

    [self.collectionView.collectionViewLayout invalidateLayout]; 

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> __nonnull context) { 
     [self.collectionView.collectionViewLayout invalidateLayout]; 
    } completion:^(id<UIViewControllerTransitionCoordinatorContext> __nonnull context) { 
     //finished 
    }]; 
} 

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    //collectionView.bounds.size is not always correct here after invalidating layout as explained above 
} 

Я также попытался invaliding его в блоке завершения, но она до сих пор не использует правильные представления коллекции границ.

Если я снова аннулирую макет в viewWillAppear, это использует правильные рамки просмотра коллекций, которые устраняют проблему при вращении с помощью модально представленного контроллера представления. Но это не обязательно, возможно, есть и другие ситуации, когда это не будет правильно оценено.

+0

Вы заглянули в http://stackoverflow.com/questions/29023473/uicollectionview-invalidate-layout-on-bounds-changes? – ozgur

+0

@ozgur Я уже пробовал, что в этом ответе да, как объяснялось выше – Joey

+0

Вы уверены, что ничего не обновляете в 'viewWillAppear()'? В описанном сценарии (вы меняете ориентацию, когда модальный контроллер завершен), когда контроллер модального представления отклоняется, вы можете получить фрейм с * предыдущей * ориентацией в 'viewWillAppear()' и правильный фрейм в 'viewDidAppear() '. Так что для меня обычно работает только обновление макета в 'viewWillTransitionToSize'. –

ответ

13

Я знаю, в чем проблема. Когда вы вызываете invalidateLayout внутри animateAlongsideTransition (либо в блоке анимации, либо в блоке завершения), он фактически не пересчитывает макет, если на полноэкранном режиме представлен контроллер модального представления (но он будет, если он находится в текущем контексте). Но это будет аннулировать его, если вы сделаете недействительным его вне блока анимации, как я делал. В то время, однако, представление коллекции не было изложено для нового размера, что объясняет, почему я видел старое значение его границ. Причиной такого поведения является invalidateLayout, что не сразу приводит к пересчету макета - он должен появиться во время следующего прохода макета. Этот макет не происходит, если на полноэкранном режиме имеется установленный в режиме просмотра вид контроллер. Чтобы заставить пропустить макет, просто вызовите [self.collectionView layoutIfNeeded]; сразу после [self.collectionView.collectionViewLayout invalidateLayout];, все еще в блоке animateAlongsideTransition. Это приведет к тому, что макет будет пересчитан, как ожидалось.

+0

ваш ответ сделал мой день .. Спасибо много! –

Смежные вопросы