ios 为什么当单元格全屏时 UICollectionView 会记录错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23596181/
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-31 00:07:12  来源:igfitidea点击:

Why does UICollectionView log an error when the cells are fullscreen?

iosobjective-cios7uicollectionview

提问by Wes

I have a UICollectionViewControllerusing a UICollectionViewFlowLayoutwhere my itemSizeis the size of the UICollectionView. Basically, this is a line layout of cells where each cell is fullscreen and scrolls horizontally.

我有一个UICollectionViewControllerusing a UICollectionViewFlowLayout,其中 myitemSizeUICollectionView. 基本上,这是一个单元格的行布局,其中每个单元格都是全屏的并水平滚动。

In my UICollectionViewFlowLayoutsubclass, I have overridden prepareLayoutas follows:

在我的UICollectionViewFlowLayout子类中,我重写prepareLayout如下:

- (void)prepareLayout {
    self.itemSize = self.collectionView.frame.size;
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.collectionView.pagingEnabled = YES;
    self.minimumLineSpacing = 0.0;
    self.minimumInteritemSpacing = 0.0;
    self.sectionInset = UIEdgeInsetsZero;
    self.footerReferenceSize = CGSizeZero;
    self.headerReferenceSize = CGSizeZero;
}

The UICollectionViewControlleris very basic returning 10 items in one section. I've included a sample project on GitHubfor more detail.

UICollectionViewController是非常基本的一个部分返回 10 个项目。我在 GitHub 上包含了一个示例项目以获取更多详细信息。

Everything appears to be set up correctly. It looks right in the simulator and on the device but, when the collection view is displayed, there is an error logged to the console:

一切似乎都设置正确。它在模拟器和设备上看起来都不错,但是当显示集合视图时,控制台会记录一个错误:

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

Note also that the collection view controller in my example is in a navigation controller and while that doesn't look particularly necessary in the example, in my real-world case I need the collection view in a navigation controller.

另请注意,我的示例中的集合视图控制器位于导航控制器中,虽然在示例中看起来不是特别必要,但在我的实际情况中,我需要导航控制器中的集合视图。

回答by Wes

There is a property on UIViewControllerautomaticallyAdjustsScrollViewInsets–that defaults to YES. This means that when a UIViewControllerhas a UIScrollViewin its view hierarchy–which is true of a UICollectionViewController–the contentInsetproperty of that scroll view is adjusted automatically to account for screen areas consumed by the status bar, navigation bar, and toolbar or tab bar.

UIViewControllerautomaticallyAdjustsScrollViewInsets–上有一个属性,默认为YES。这意味着当 a在它的视图层次结构中UIViewController有 aUIScrollView时——这对 a 来说是真的UICollectionViewController——contentInset滚动视图的属性会自动调整以考虑状态栏、导航栏和工具栏或标签栏消耗的屏幕区域。

The documentation for that property states:

该属性的文档说明:

automaticallyAdjustsScrollViewInsets

Specifies whether or not the view controller should automatically adjust its scroll view insets.

@property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets

Discussion

Default value is YES, which allows the view controller to adjust its scroll view insets in response to the screen areas consumed by the status bar, navigation bar, and toolbar or tab bar. Set to NO if you want to manage scroll view inset adjustments yourself, such as when there is more than one scroll view in the view hierarchy.

自动调整ScrollViewInsets

指定视图控制器是否应自动调整其滚动视图插入。

@property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets

讨论

默认值为 YES,它允许视图控制器根据状态栏、导航栏和工具栏或选项卡栏消耗的屏幕区域调整其滚动视图插入。如果您想自己管理滚动视图插入调整,请设置为 NO,例如当视图层次结构中有多个滚动视图时。

The solution is to set automaticallyAdjustsScrollViewInsetsto NOsomewhere in your UICollectionViewControllersubclass, such as in viewDidLoad:

解决方案是设置automaticallyAdjustsScrollViewInsets到子类中的NO某个位置UICollectionViewController,例如在viewDidLoad

- (void)viewDidLoad {
    [super viewDidLoad];
    self.automaticallyAdjustsScrollViewInsets = NO;
}

I have put an example project on GitHubthat illustrates this problem and solution. There are two branches: with_errorand fixed_error. Here is a diff of the change on GitHub.

在 GitHub 上放了一个示例项目来说明这个问题和解决方案。有两个分支:with_errorfixed_error。这是GitHub 上更改差异

回答by Legonaftik

iOS 11 update:automaticallyAdjustsScrollViewInsetsis deprecated in iOS 11.0.

iOS 11 更新:automaticallyAdjustsScrollViewInsets在 iOS 11.0 中已弃用。

Apple recommends using UIScrollView's contentInsetAdjustmentBehaviormethod instead. I set this value to .neverand the error has gone. You can also set this property in Interface Builder.

Apple 建议改用UIScrollViewcontentInsetAdjustmentBehavior方法。我将此值设置为.never并且错误消失了。您也可以在 Interface Builder 中设置此属性。

回答by Tamás Sengel

This issue just occured to me on 3x screens (namely the iPhone 6 Plus.) As it turned out, the autolayout engine did not really like infinite floating point values (such as .33333333), so my solution was to floorthe return height in sizeForItemAt:indexPath:.

这个问题只是在 3x 屏幕(即 iPhone 6 Plus)上发生在我身上。事实证明,自动布局引擎并不真正喜欢无限浮点值(例如 .33333333),所以我的解决方案是 .33333333 中floor的返回高度sizeForItemAt:indexPath:

return CGSize(width: preferredWidth, height: floor(preferredHeight))

回答by Stunner

I encountered this problem when rotating the device from portrait to landscape, back to portrait. You want to invalidate the collectionView's layout upon device rotation and before the call to super, like so:

我在将设备从纵向旋转到横向,再旋转回纵向时遇到了这个问题。您希望collectionView在设备旋转时和调用 super 之前使 的布局无效,如下所示:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    // Causes collection view cells to be resized upon orientation change.
    // Important that this is called *before* call to super in order to prevent error from being logged to console.
    [self.collectionView.collectionViewLayout invalidateLayout];

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    //...
}

回答by Hardy_Germany

Like Stunner, I had the same problem when rotating from landscape (picture using full width) to portrait mode. His suggestion was the only one which really helped.

像 Stunner 一样,从横向(使用全宽的图片)旋转到纵向模式时,我遇到了同样的问题。他的建议是唯一真正有帮助的建议。

Attached the code with latest Swift for his ObjC example ... and as a bonus, my code to find the center cell of the collection view. Works quite nice ;-)

为他的 ObjC 示例附加了最新的 Swift 代码......作为奖励,我的代码用于查找集合视图的中心单元格。效果很好;-)

/**
 -----------------------------------------------------------------------------------------------

 viewWillTransition()

 -----------------------------------------------------------------------------------------------
 */
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

    // find cell in the center of the screen and store it in a global variable
    let center = self.view.convert((self.collectionView!.center), to: self.collectionView)

    // get the indexPath for the cell in the center of the current screen
    if let index = collectionView!.indexPathForItem(at: center) {

        // store it in a class property
        self.indexPathOfCenterCell = index
    }

    // force recalculation of margins, borders, cell sizes etc.
    self.collectionView?.collectionViewLayout.invalidateLayout()

    // inform UIKit about it    
    super.viewWillTransition(to: size, with: coordinator)
}

回答by Nithyashree

This way had worked for me perfectly!.

这种方式对我来说非常有效!

I just subtracted the top and bottom insets from the view's height as said in that error.

如该错误所述,我只是从视图的高度中减去了顶部和底部的插图。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: view.frame.width , height: view.frame.height - (view.safeAreaInsets.top + view.safeAreaInsets.bottom)) }

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: view.frame.width , height: view.frame.height - (view.safeAreaInsets.top + view.safeAreaInsets.bottom)) }

I hope it helps!

我希望它有帮助!

回答by Anton Tropashko

ios 10: topmost view was not connected to the view outlet

ios 10:最上面的视图没有连接到视图插座

回答by Prashant Tukadiya

I had similar issue.

我有类似的问题。

After load cell which is full width and some height of screen. on some condition I changed the height of cell then I was getting the same error

在全宽和一些屏幕高度的称重传感器之后。在某些情况下,我改变了单元格的高度,然后我得到了同样的错误

to fix this

解决这个问题

I used

我用了

   func updateHeightPerRatio(with image:UIImage) {
    let ratio = collectionView.bounds.width / image.size.width
    constHeightCollectionView .constant =  ceil(image.size.height * ratio)
    collectionView.reloadData()
    collectionView.performBatchUpdates({
        collectionView.layoutIfNeeded()
    }) { (completed) in
        self.collectionView.reloadData()
        self.layoutIfNeeded()
    }
}

Solution is reload data then perform batchupdate with that collection view re -calculate the frames . after that reload collectionview again it will apply calculated frames to cell

解决方案是重新加载数据,然后使用该集合视图执行批量更新,重新计算帧。再次重新加载 collectionview 后,它会将计算出的帧应用于单元格

And now there is no log for issue now.

现在没有问题日志。

Hope it is helpful

希望它有帮助

回答by Lenda

I was getting the same error when I was trying to embed a UICollectionViewin a UITableView. I was generating a new UICollectionViewin each UITableViewcell, but I did not put any constraints on the height of that UICollectionView. So, when I put a constraint on the height, that error is gone!

当我尝试将 a 嵌入UICollectionViewUITableView. 我UICollectionView在每个UITableView单元格中生成一个新的,但我没有对那个UICollectionView. 所以,当我对高度施加限制时,这个错误就消失了!

回答by Ammar Mujeeb

In my case I have to reduce bottom inset (from 20 to 0) of cell as I have reduced 20 from height of collectionview From

在我的情况下,我必须减少单元格的底部插入(从 20 到 0),因为我从 collectionview 的高度减少了 20

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
-        return UIEdgeInsets(top: 10, left: 10, bottom: 20, right: 10)
+        return UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 10)
     }

func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let size = CGSize(width: 350, height: collectionView.bounds.size.height - 20)
        return size
    }