UICollectionViewFlowLayout在方向更改时不会失效

我有一个带有UICollectionViewFlowLayout的UICollectionView。 我还实现了UICollectionViewDelegateFlowLayout协议。

在我的数据源中,我有一堆UIViewControllers响应自定义协议,所以我可以询问它们的大小和其他一些东西。

在请求sizeForItemAtIndexPath:的FlowLayout委托中,我返回从我的协议获得的项目大小。 实现我的协议的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:。

希望你明白我的意思。 如果您需要其他信息,请告诉我:)

一种解决方案是使用KVO并监听对集合视图的superview框架的更改。 调用-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]; } 

这个答案很晚,但接受的答案对我不起作用。 我同情OP想要一个即兴发射的UICollectionViewFlowLayout。 我建议在视图控制器中使布局无效实际上是最好的解决方案。

我想要一个单独的水平滚动细胞线,在视图中居中,纵向和横向。

我将UICollectionViewFlowLayout子类化。

我重写prepareLayout重新计算插入,然后调用[super prepareLayout]。

我覆盖了collectionViewContentSize的getter,以确保内容大小正确。

即使边界随着重新定向而变化,布局也不会自动失效。

 - (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维护方向之间的滚动位置。 只有当它是正方形时,相同的单元格才会居中。

我在这里使用了两个答案的组合来做我们都想要做的事情真的是使集合视图看起来像一个表视图但不使用UITableView并在单个列中获取项目(很可能)

 - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.collectionView.collectionViewLayout invalidateLayout]; } 

@ 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() } } 

我不知道它是否对某人有帮助,但最后一个答案都没有帮助我,因为我在UIScrollView使用了一些UIViews

我会根据某些事件以编程方式打开UIViews。 所以我不能使用- (void) willRotateToInterfaceOrientation:invalidateLayoutreloadData因为:
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帮助我修复它。

iOS8:我能够使警告静音的唯一方法是在转换到较大尺寸时和转换到旋转到较小尺寸之前调用无效。

  self.sizeForCollectionView = size; //used to determine collectionview size in sizeForItem if (size.width <= size.height) { [self.collectionView.collectionViewLayout invalidateLayout]; } [coordinator animateAlongsideTransition:^(id context) { if (size.width > size.height) { [self.collectionView.collectionViewLayout invalidateLayout]; } } completion:^(id context) { }]; 

@ 0mahc0的答案对我有用,但只是部分。

我没有旋转问题,因为我强制我的应用程序仅在纵向模式下,但我的解决方案可以帮助其他人遇到同样的问题。

每次出现视图时都会显示警告。 警告的原因非常清楚,我们已经在UICollectionView的左右两侧定义了部分插入。 检查界面构建器,您将在度量标准中看到定义的值。

@ 0mahc0的解决方案有效,但我想将单元格拉伸到最大宽度,所以我删除了截面的插图,否则我将左右边缘。

 - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{ return UIEdgeInsetsZero; } 

您可以转到界面构建器并将值更改为左右插入的零,而不是实现委托方法。