38

我们使用 UICollectionView 来显示覆盖全屏的单元格(减去状态和导航栏)。单元格大小设置为self.collectionView.bounds.size

- (void)viewWillAppear:(BOOL)animated
{
    //
    // value isn't correct with the top bars until here
    //
    CGSize tmpSize = self.collectionView.bounds.size;
    _currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
}

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout*)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    return _currentCellSize;
}

这将为每个设备设置正确的大小。每个单元格都被定义为没有插图,并且布局没有页眉或页脚。但是,当我们从纵向旋转到横向时,我们会得到以下“抱怨”:

the behavior of the UICollectionViewFlowLayout is not defined because:
the item height must be less that the height of the UICollectionView minus the section insets top and bottom values.

现在我理解了这个错误,但是我们重置了单元格的大小并使用了旋转过渡中内置的流布局:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    //self.collectionView.bounds are still the last size...not the new size here
}
- (void)didRotateFromInterfaceOrientation: UIInterfaceOrientation)fromInterfaceOrientation
{
    CGSize tmpSize = self.collectionView.bounds.size;
    _currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
    [self.collectionView performBatchUpdates:nil completion:nil];//this will force the redraw/size of the cells.
}

单元格在横向中正确渲染。

似乎 Flow Layout 看到了旧的单元格大小(这会导致抱怨,因为它太高了),但确实读取/渲染了didRotateFromInterfaceOrientation.

有没有办法摆脱投诉?

我们尝试在设备旋转过渡期间找到另一个挂钩,该挂钩可以访问正确的目标屏幕尺寸(与当前屏幕尺寸相比),但没有成功。调试输出显示投诉发生在 之后willRotateToInterfaceOrientation但之前didRotateFromInterfaceOrientation

我们也验证了显而易见的;如果我们将单元格高度设置为小于横向屏幕高度的固定大小,则不会发生投诉。此外,从横向旋转回纵向时不会发生投诉。

一切运行良好,并且渲染正确。然而,这种抱怨让我们感到担忧。其他人有任何想法或解决方案吗?

4

21 回答 21

36

我得到了同样的警告。对“reloadData”方法不满意,我发现在设置集合视图的框架[self.collectionView.collectionViewFlowLayout invalidateLayout] 之前调用会消除警告并产生预期的结果。

于 2013-03-25T20:28:02.413 回答
9

不要再向这个满载但不被接受的芭比娃娃扔虾。

- (CGSize)collectionView:(UICollectionView *)collectionView 
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    [collectionView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
    return CGSizeMake(100, collectionView.frame.size.height);
}

在返回单元格大小之前设置内容插图对我有用。

笔记:

我在故事板中使用容器视图来加载 UIViewController 中的集合视图。我尝试在情节提要中的 flowLayout 对象上设置它。故事板中的集合视图。并覆盖其中一个 UICollectionViewDelegateFlowLayout;虽然我不记得是哪一个。我也不确定这是否适用于垂直布局。

于 2014-06-27T21:30:07.833 回答
6

[UIViewController willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration]

我打电话了,[UICollectionViewLayout invalidateLayout]似乎工作得很好。

于 2013-07-11T01:44:00.463 回答
4

我解决了。

你应该让flowLayout的高度小于collcetionView.frame.size.height。

 [flowLayout setItemSize:CGSizeMake(width, height)];


 collectionView.frame = CGRectMake(12, 380, 290, 80);
于 2015-02-10T04:42:23.530 回答
4

许多解决方案都建议添加invalidateLayout-willAnimateRotationToInterfaceOrientation但自 iOS 8 以来已弃用。

对于 iOS 8 及更高版本,请使用:

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

    [self.collectionView.collectionViewLayout invalidateLayout];
}

感谢@user7097242 的评论,这里有一个 swift4 版本:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    self.collectionView.collectionViewLayout.invalidateLayout()
}
于 2016-03-31T12:49:46.330 回答
2

刚刚遇到并解决了同样的问题。由于我的解决方案更符合您的要求并且与任何现有答案都不匹配,因此我已将其发布在这里。

#define NUMBER_OF_CELLS_PER_ROW 1

- (UICollectionViewFlowLayout *)flowLayout {
    return (UICollectionViewFlowLayout *)self.collectionViewLayout;
}

- (CGSize)itemSizeInCurrentOrientation {
    CGFloat windowWidth = self.collectionView.window.bounds.size.width;

    CGFloat width = (windowWidth - (self.flowLayout.minimumInteritemSpacing * (NUMBER_OF_CELLS_PER_ROW - 1)) - self.flowLayout.sectionInset.left - self.flowLayout.sectionInset.right)/NUMBER_OF_CELLS_PER_ROW;

    CGFloat height = 80.0f;

   return CGSizeMake(width, height);
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.flowLayout invalidateLayout];
    self.flowLayout.itemSize = [self itemSizeInCurrentOrientation];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    // Now that the rotation is complete, load the cells.
    [self.collectionView reloadData];
}
于 2013-10-22T16:45:18.040 回答
2

这对我有用:(希望它也对你有用!)

- (void)viewWillLayoutSubviews 
{     
     self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height);    
     [self.flowLayout invalidateLayout];
}

- (void)viewDidLayoutSubviews     
{
    self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height); 
}
于 2015-04-03T07:50:13.147 回答
2

我的修复就像取消选中 IB 中视图控制器的“调整滚动视图插图”一样简单,因为我需要我的导航栏是半透明的。

于 2014-11-03T08:37:45.743 回答
2

我遇到了同样的问题。如果集合视图在纵向显示时,单元格将在旋转到横向时消失。我在这里结合了其他答案来解决这个问题。

我将视图(包含 UICollectionView 的视图)设置为接收UIDeviceOrientationDidChangeNotification通知。在响应该通知的方法中,调整 UICollectionView 框架后,我执行了以下操作:

- (void)orientationChanged:(NSNotification *)notification
{
    CGSize size = (CGSize){self.frame.size.width - 2*kContentMargin, self.frame.size.height - 2*kContentMargin};
    [self.collectionView.collectionViewLayout setItemSize:size];

    [self.collectionView.collectionViewLayout invalidateLayout];
    [self.collectionView reloadData];
}

请注意, UICollectionView 的框架在旋转时会自动设置,因为它的 resizingMask 在初始化时设置为此:

self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
于 2013-07-25T17:58:26.900 回答
2

这为我解决了它:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

我正在使用这个委托方法来设置大小:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

我可以从那里在旋转后使用正确的框架:

self.collectionView.frame.size
于 2014-02-25T09:17:04.130 回答
1

我遇到了同样的问题。这就是我解决它的方法。希望能帮助到你

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(    NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [self.collectionView reloadData];
}
于 2013-03-13T19:18:37.460 回答
1

尝试这个...

UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout;

layout.itemSize = CGSizeMake(0.1, 0.1);

它对我有用。

于 2014-01-29T10:02:23.840 回答
0

我使用了UICollectionViewFlowLayoutInvalidationContext,我在其中计算了新的偏移量,使其保持相同的内容偏移量。我自己的函数collectionViewSizeForOrientation:返回正确的大小。它并不完美,但至少它不是粗略的:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    CGSize fromCollectionViewSize = [self collectionViewSizeForOrientation:[self interfaceOrientation]];
    CGSize toCollectionViewSize = [self collectionViewSizeForOrientation:toInterfaceOrientation];

    CGFloat currentPage = [_collectionView contentOffset].x / [_collectionView bounds].size.width;
    NSInteger itemCount = [_collectionView numberOfItemsInSection:0];

    UICollectionViewFlowLayoutInvalidationContext *invalidationContext = [[UICollectionViewFlowLayoutInvalidationContext alloc] init];

    [invalidationContext setContentSizeAdjustment:CGSizeMake(toCollectionViewSize.width * itemCount - fromCollectionViewSize.width * itemCount, toCollectionViewSize.height - fromCollectionViewSize.height)];
    [invalidationContext setContentOffsetAdjustment:CGPointMake(currentPage * toCollectionViewSize.width - [_collectionView contentOffset].x, 0)];

    [[_collectionView collectionViewLayout] invalidateLayoutWithContext:invalidationContext];

    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

collectionViewSizeForOrientation:在我的情况下,假设插入和项目间距为0:

- (CGSize)collectionViewSizeForOrientation:(UIInterfaceOrientation)orientation
{
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;

    CGFloat width = UIInterfaceOrientationIsLandscape(orientation) ? MAX(screenSize.width, screenSize.height) : MIN(screenSize.width, screenSize.height);
    CGFloat height = UIInterfaceOrientationIsLandscape(orientation) ? MIN(screenSize.width, screenSize.height) : MAX(screenSize.width, screenSize.height);

    return CGSizeMake(width, height);

}

于 2014-11-03T15:59:04.263 回答
0

您可以继承UICollectionView和覆盖setBounds:. 在调用之前[super setBounds:],可以将项目大小调整到新的边界。
您应该检查边界的大小是否已更改,因为setBounds:在滚动时也会调用。

于 2013-07-28T16:59:49.090 回答
0

我知道这是一个老问题,但我刚遇到同样的问题,花了一个小时来解决它。我的问题是,似乎 UICollectionView 的帧大小总是错误的(高度与容器不匹配),而我在调用 UICollectionView Flow 布局委托之前设置了帧大小。因此,我在方法上再次设置了 UICollectionView 帧大小:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

这就是诀窍。高度现在显示正确并且警告消失了。

于 2015-03-03T04:46:54.547 回答
0

以下代码为我修复了它:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return self.collectionView.frame.size;
}
于 2014-05-29T17:22:19.707 回答
0

我在调整 UICollectionView 的框架时遇到了同样的问题。如果我使用 FlowLayout 上的委托方法来返回单元格的大小(将根据包含的 UICollectionView 的大小进行更新),当我调整(更小)UICollectionView 的框架时,我会收到错误消息,因为它在抱怨之前似乎没有要求代表提供更新的尺寸信息。它最终会在重绘时向委托方法询问大小信息,但在我分配新的框架方法时它仍然会发出警告。为了摆脱警告,我之前明确设置了 UICollectionViewFlowLayout 对象的 itemSize 属性我将框架设置为一个新的更小的值。我的情况很简单,我认为我可以在这一点上进行 itemSize 计算(因为我在集合视图中的所有项目都是相同的大小),而不是依赖于委托方法。只是在实现委托方法的同时设置 itemSize 属性并不能解决问题,因为我认为如果检测到委托方法已实现,它会忽略 itemSize 的值(如果它知道它在那里,为什么不调用它?!)。希望这会有所帮助 - 也许您也可以在旋转之前显式设置 itemSize。

于 2013-02-06T18:26:21.123 回答
0

只是为了抑制警告并(可能,不确定)在返回大小之前提高性能

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

检查视图控制器是否正在旋转,是否返回一些相对较小的尺寸,如CGSizeMake(0.1, 0.1)

于 2013-05-24T07:12:57.860 回答
0

试图找到一种解决方案来消除 iOS 7 上的这些警告对我来说很困难。我最终求助于子类UICollectionView化并添加了以下代码。

- (void)setFrame:(CGRect)frame
{
    if (!iOS8 && (frame.size.width != self.frame.size.width))
    {
        [self.collectionViewLayout invalidateLayout];
    }

    [super setFrame:frame];
}

有些人可能想用CGSizeEqualToSize().

于 2015-03-25T01:32:22.913 回答
0

注意:就我而言,我发现我们正在设置有问题的preferredContentSize属性UIViewController。如果您发现这是您的情况,您可能必须处理协议的以下方法UICollectionViewDelegateFlowLayout

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGSize size = collectionViewLayout.collectionView.bounds.size;
    ...
    return size;
}
于 2016-03-01T22:24:58.423 回答
0

在 didRotateFromInterfaceOrientation 的末尾尝试:

[self.collectionView setNeedsLayout]

如果它不起作用,请尝试将所有这些东西从 didRotateFromInterfaceOrientation 移动到 willRotateToInterfaceOrientation

于 2015-11-15T16:42:45.557 回答