将设备旋转到风景时出现UICollectionViewFlowLayout尺寸警告
我们使用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.
现在我明白了这个错误,但是我们重置了单元格的大小,并使用循环转换中构build的stream布局:
-(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. }
单元格在景观中正确呈现。
看起来好像stream布局看到旧的单元格大小(这会导致抱怨,因为它会太高),但读取/呈现在didRotateFromInterfaceOrientation
设置新的单元格大小。
有没有办法摆脱投诉?
我们已经尝试在设备旋转转换期间find另一个挂钩,该转换有权访问正确的目标屏幕大小(vs当前屏幕大小),但没有运气。 debugging输出显示投诉发生在willRotateToInterfaceOrientation
之后,但didRotateFromInterfaceOrientation
之前。
我们也证实了这一点, 如果我们将单元高度设置为小于景观屏幕高度的固定尺寸,则不会发生投诉。 此外,从横向旋转到纵向时,投诉不会发生。
一切运行良好,并呈现正确。 但是这个投诉令我们感到担忧。 任何人有任何想法或解决scheme?
我收到了同样的警告。 不满意“reloadData”方法,我发现在设置集合视图的框架之前调用[self.collectionView.collectionViewFlowLayout invalidateLayout]
警告并产生预期的结果。
不要把另一只虾放在这个装满的,但不被接受的芭比娃娃上。
- (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对象上设置它。 故事板中的collections视图。 并覆盖其中一个UICollectionViewDelegateFlowLayout; 虽然我不记得哪一个。 我也不确定这是否适用于垂直布局。
在
[UIViewController willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration]
我调用, [UICollectionViewLayout invalidateLayout]
,似乎工作良好。
我解决了它。
你应该让flowLayout的高度小于collcetionView.frame.size.height。
[flowLayout setItemSize:CGSizeMake(width, height)]; collectionView.frame = CGRectMake(12, 380, 290, 80);
我遇到了同样的问题。 如果纵向方向显示集合视图,则单元在旋转到横向时将消失。 我在这里做了其他答案的组合来解决这个问题。
我将我的视图(包含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;
刚刚遇到并解决了同样的问题。 由于我的解决scheme更符合你所要求的和现有的答案不匹配,我已经在这里贴出来。
#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]; }
这为我解决了这个问题:
-(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
我的解决方法就像取消选中IB中视图控制器的“Adjust Scroll View Insets”一样简单,因为我需要我的导航栏变成半透明的。
这对我有用:(希望它也适用于你!)
- (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); }
很多解决scheme都build议将invalidateLayout
添加到willAnimateRotationToInterfaceOrientation
– 但是从iOS 8开始,这已经被弃用了。
对于iOS 8/9,请使用:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.collectionView.collectionViewLayout invalidateLayout]; }
我面临同样的问题。 这是我如何解决它。 希望能帮助到你
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:( NSTimeInterval)duration { [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; [self.collectionView reloadData]; }
尝试这个…
UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout; layout.itemSize = CGSizeMake(0.1, 0.1);
这对我很有用。
在调整UICollectionView的框架时遇到同样的问题。 如果我使用FlowLayout上的委托方法来返回单元格的大小(这将根据包含UICollectionView的大小进行更新),当我调整(较小)的UICollectionView的框架时,我会得到错误消息,因为它在抱怨之前似乎没有向代表询问更新的大小信息。 它最终会在重绘时询问委托方法的大小信息,但是在我分配新的框架方法的时候仍然会发出警告。 为了摆脱这个警告,我明确地设置了UICollectionViewFlowLayout对象的itemSize属性, 然后将帧设置为一个更小的值。 我的情况很简单,我认为我可以放弃在此时进行itemSize计算(因为集合视图中的所有项都具有相同的大小),而不依赖于委托方法。 只是设置itemSize属性,而离开委托方法实施并没有解决问题,因为我认为它忽略了itemSize的值,如果它检测到委托方法已经实现(如果它知道它在那里,为什么不叫它?!)。 希望这有助于 – 也许你也可以显式设置itemSize之前旋转。
只是为了抑制警告和(可能不确定)提高性能,你可以在返回大小之前
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
检查视图控制器是否在旋转过程中,如果它返回一些像CGSizeMake(0.1, 0.1)
那样相对较小的尺寸CGSizeMake(0.1, 0.1)
您可以UICollectionView
并覆盖setBounds:
UICollectionView
在调用[super setBounds:]
,可以将项目大小调整到新的边界。
您应该检查边界的大小是否已经改变,因为setBounds:
在滚动时也被调用。
以下代码修复了我的问题:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return self.collectionView.frame.size; }
我已经使用了一个UICollectionViewFlowLayoutInvalidationContext
,其中我计算新的偏移,使它保持相同的内容偏移量。 我自己的函数collectionViewSizeForOrientation:
返回适当的大小。 它不完美,但至less不是粗略的:
- (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);
}
试图find一个解决scheme来消除iOS 7上的这些警告对我来说是困难的。 我结束了诉诸UICollectionView
我的UICollectionView
并添加下面的代码。
- (void)setFrame:(CGRect)frame { if (!iOS8 && (frame.size.width != self.frame.size.width)) { [self.collectionViewLayout invalidateLayout]; } [super setFrame:frame]; }
有些人可能想用CGSizeEqualToSize()
做一个完整的大小检查。
尝试在didRotateFromInterfaceOrientation的末尾:
[self.collectionView setNeedsLayout]
如果它不起作用尝试将所有这些东西从didRotateFromInterfaceOrientation移动到willRotateToInterfaceOrientation
注意:就我而言,我发现我们正在设置UIViewController
的preferredContentSize
属性。 如果您发现这是您的情况,您可能需要处理以下UICollectionViewDelegateFlowLayout
协议的方法:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { CGSize size = collectionViewLayout.collectionView.bounds.size; ... return size; }
我知道这是一个古老的问题,但我也遇到了同样的问题,花了一个小时才解决问题。 我的问题是,似乎UICollectionView的框架大小总是错误的(高度不匹配容器),而我调用UICollectionView Flow布局委托之前设置帧的大小。 所以,我再次在方法上设置UICollectionView的帧大小:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
那就是诀窍。 现在高度正确显示,警告消失。