我试图得到自我大小UICollectionViewCells工作与自动布局,但我似乎不能让单元格大小自己的内容。我很难理解如何从单元格的contentView内的内容更新单元格的大小。

下面是我尝试过的设置:

自定义UICollectionViewCell,在它的contentView中有一个UITextView。 UITextView的滚动被禁用。 contentView的水平约束是:"H:|[_textView(320)]",也就是说UITextView被固定在单元格的左边,显式宽度为320。 contentView的垂直约束是:"V:|-0-[_textView]",也就是说UITextView固定在单元格的顶部。 UITextView有一个高度约束设置为常数,UITextView报告将适合文本。

下面是单元格背景设置为红色,UITextView背景设置为蓝色时的效果:

我把我一直在GitHub上玩的项目放在这里。


当前回答

更新更多信息:

If you use flowLayout.estimatedItemSize, suggest use iOS8.3 later version. Before iOS8.3, it will crash [super layoutAttributesForElementsInRect:rect];. The error message is *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil' Second, in iOS8.x version, flowLayout.estimatedItemSize will cause different section inset setting did not work. i.e. function: (UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:.

其他回答

对任何可能有帮助的人,

如果设置了estimatedItemSize,我就会发生严重的崩溃。即使我在numberOfItemsInSection中返回0。因此,单元格本身和它们的自动布局不是导致崩溃的原因……collectionView刚刚崩溃,即使是空的,这只是因为estimatedItemSize被设置为自大小。

在我的例子中,我重新组织了我的项目,从一个包含collectionView的控制器到一个collectionViewController,它工作了。

图。

我尝试使用estimatedItemSize,但在插入和删除单元格时,如果estimatedItemSize不完全等于单元格的高度,则有一堆错误。我停止设置estimatedItemSize,并通过使用原型单元格实现动态单元格。这是如何做到的:

创建这个协议:

protocol SizeableCollectionViewCell {
    func fittedSize(forConstrainedSize size: CGSize)->CGSize
}

在你的自定义UICollectionViewCell中实现这个协议:

class YourCustomCollectionViewCell: UICollectionViewCell, SizeableCollectionViewCell {

    @IBOutlet private var mTitle: UILabel!
    @IBOutlet private var mDescription: UILabel!
    @IBOutlet private var mContentView: UIView!
    @IBOutlet private var mTitleTopConstraint: NSLayoutConstraint!
    @IBOutlet private var mDesciptionBottomConstraint: NSLayoutConstraint!

    func fittedSize(forConstrainedSize size: CGSize)->CGSize {

        let fittedSize: CGSize!

        //if height is greatest value, then it's dynamic, so it must be calculated
        if size.height == CGFLoat.greatestFiniteMagnitude {

            var height: CGFloat = 0

            /*now here's where you want to add all the heights up of your views.
              apple provides a method called sizeThatFits(size:), but it's not 
              implemented by default; except for some concrete subclasses such 
              as UILabel, UIButton, etc. search to see if the classes you use implement 
              it. here's how it would be used:
            */
            height += mTitle.sizeThatFits(size).height
            height += mDescription.sizeThatFits(size).height
            height += mCustomView.sizeThatFits(size).height    //you'll have to implement this in your custom view

            //anything that takes up height in the cell has to be included, including top/bottom margin constraints
            height += mTitleTopConstraint.constant
            height += mDescriptionBottomConstraint.constant

            fittedSize = CGSize(width: size.width, height: height)
        }
        //else width is greatest value, if not, you did something wrong
        else {
            //do the same thing that's done for height but with width, remember to include leading/trailing margins in calculations
        }

        return fittedSize
    }
}

现在让你的控制器符合UICollectionViewDelegateFlowLayout,在它里面,有这个字段:

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout {
    private var mCustomCellPrototype = UINib(nibName: <name of the nib file for your custom collectionviewcell>, bundle: nil).instantiate(withOwner: nil, options: nil).first as! SizeableCollectionViewCell
}

它将被用作一个原型单元格来绑定数据,然后确定该数据如何影响您想要动态的维度

最后,必须实现uicollectionviewdelegatflowlayout的collectionView(:layout:sizeForItemAt:):

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    private var mDataSource: [CustomModel]

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)->CGSize {

        //bind the prototype cell with the data that corresponds to this index path
        mCustomCellPrototype.bind(model: mDataSource[indexPath.row])    //this is the same method you would use to reconfigure the cells that you dequeue in collectionView(:cellForItemAt:). i'm calling it bind

        //define the dimension you want constrained
        let width = UIScreen.main.bounds.size.width - 20    //the width you want your cells to be
        let height = CGFloat.greatestFiniteMagnitude    //height has the greatest finite magnitude, so in this code, that means it will be dynamic
        let constrainedSize = CGSize(width: width, height: height)

        //determine the size the cell will be given this data and return it
        return mCustomCellPrototype.fittedSize(forConstrainedSize: constrainedSize)
    }
}

就是这样。在collectionView(:layout:sizeForItemAt:)中返回单元格的大小,以这种方式防止我不得不使用estimatedItemSize,并且插入和删除单元格工作得很好。

对丹尼尔·加拉斯科的回答做了一些关键的修改,解决了我所有的问题。不幸的是,我还没有足够的声誉来直接评论。

在第一步,当使用自动布局时,简单地添加一个单亲UIView到单元格。单元格内的所有东西都必须是父视图的子视图。这解决了我所有的问题。虽然Xcode会自动为UITableViewCells添加这个,但它不会(但应该)为UICollectionViewCells添加这个。根据文件:

要配置单元格的外观,请在contentView属性的视图中添加将数据项的内容作为子视图显示所需的视图。不要直接向单元格本身添加子视图。

然后完全跳过步骤3。这是不需要的。

更新更多信息:

If you use flowLayout.estimatedItemSize, suggest use iOS8.3 later version. Before iOS8.3, it will crash [super layoutAttributesForElementsInRect:rect];. The error message is *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil' Second, in iOS8.x version, flowLayout.estimatedItemSize will cause different section inset setting did not work. i.e. function: (UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:.

在viewDidLoad()上添加flowLayout override func viewDidLoad() { super.viewDidLoad () if let flowLayout = infoCollection。collectionViewLayout一样吗?UICollectionViewFlowLayout { estimateditemsize = CGSize(宽度:1,高度:1) } } 此外,设置一个UIView为单元的mainContainer,并在其中添加所有必需的视图。 参考这个很棒的,令人兴奋的教程,以获得进一步的参考: 在iOS 9和10中使用自动布局自动调整单元格的UICollectionView