ios 将设备旋转到横向时的 UICollectionViewFlowLayout 大小警告

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14469251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:58:14  来源:igfitidea点击:

UICollectionViewFlowLayout Size Warning When Rotating Device to Landscape

iosobjective-cuicollectionviewuicollectionviewlayout

提问by Mikel Nelson

We are using a UICollectionView to display cell that cover the full screen (minus the status and nav bar). The cell size is set from self.collectionView.bounds.size:

我们使用 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;
}

This sets the correct sizing for each device. Each cell is defined to have no insets, and the layout has no header or footer. However, when we rotate from portrait to landscape we get the following "complaint":

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

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.

Now I understand this error, however we reset the size of the cell and use the flow layouts built in rotation transition:

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

-(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.
}

The cells render correctly in landscape.

单元格在横向上正确呈现。

It seems as though the Flow Layout sees the old cell size (which causes the complaint since it will be too tall), but does read/render the new cell size set in didRotateFromInterfaceOrientation.

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

Is there a way to get rid of the complaint?

有没有办法摆脱投诉?

We've tried finding another hook during a device rotate transition that has access to the correct target screen size (vs the current screen size) with no luck. Debug output shows the complaint happens after willRotateToInterfaceOrientationbut before didRotateFromInterfaceOrientation.

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

We've also verified the obvious; if we set up the cell height to be a fixed size less than the landscape screen height, the complaint doesn't occur. Also, the complaint does not occur when rotating from landscape back to portrait.

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

Everything runs fine, and renders correctly. However this complaint worries us. Anyone else have any ideas or solutions?

一切运行良好,并正确呈现。然而,这个投诉让我们感到担忧。其他人有任何想法或解决方案吗?

回答by Chris Hinkle

I was getting the same warning. Unsatisfied with the "reloadData" approach, I found that calling [self.collectionView.collectionViewFlowLayout invalidateLayout]beforesetting the frame of the collection view silenced the warning and yielded the expected results.

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

回答by Josh Bruce

Not to throw another shrimp on this loaded, yet unaccepted, barbie.

不要在这个装满但不被接受的芭比娃娃上再扔一只虾。

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

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

Setting the content insets just before returning the cell size did the trick for me.

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

Note:

笔记:

I am using a container view in a storyboard to load the collection view within a UIViewController. I tried setting this on the flowLayout object in the storyboard. The collection view in the storyboard. And overriding one of the UICollectionViewDelegateFlowLayout; though I do not remember which one. I'm also not sure if this will work for a vertical layout.

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

回答by somebody

In

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

I called the, [UICollectionViewLayout invalidateLayout]and seems to work good.

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

回答by Donny

I solved it.

我解决了。

You should just let the height of flowLayout less than collcetionView.frame.size.height.

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

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


 collectionView.frame = CGRectMake(12, 380, 290, 80);

回答by JosephH

A lot of the solutions suggest adding invalidateLayoutto willAnimateRotationToInterfaceOrientation- but this is deprecated since iOS 8.

很多的解决方案,建议增加invalidateLayoutwillAnimateRotationToInterfaceOrientation-但由于iOS的8不赞成这种方式。

For iOS 8 and higher, use:

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

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

    [self.collectionView.collectionViewLayout invalidateLayout];
}

Thanks to @user7097242's comment here is a swift4 version:

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

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    self.collectionView.collectionViewLayout.invalidateLayout()
}

回答by mayqiyue

This works for me: (and hope it also works for you!)

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

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

回答by Rick van der Linde

My fix was as simple as unchecking 'Adjust Scroll View Insets' for the view controller in IB, since I needed my navigation bar to be translucent.

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

回答by ullstrm

This solved it for me:

这为我解决了:

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

And I am using this delegate method for setting the size:

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

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

And I can from there use this with the correct frame after rotation:

我可以从那里在旋转后将其与正确的框架一起使用:

self.collectionView.frame.size

回答by Alfie Hanssen

I encountered this same issue. If the collection view was displayed when in portrait orientation, the cells would disappear when rotated to landscape. I did a combination of the other answers here to fix this.

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

I set my view (the one that contains the UICollectionView) up to receive the UIDeviceOrientationDidChangeNotificationnotification. In the method that responds to that notification, after the UICollectionView frame was adjusted, I did the following:

我将我的视图(包含 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];
}

Note that the frame of the UICollectionView is being set automatically upon rotation because its resizingMask is set to this upon initialization:

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

self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

回答by lambmj

Just encountered and fixed the same problem. Since my solution is more along the lines you were asking for and doesn't match any existing answer, I've posted it here.

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

#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];
}