UICollectionView单元格在删除具有estimatedItemSize的项目时resize

我有一个简单的项目,故事板只包含一个UICollectionViewController ,用Xcode 7.1.1 for iOS 9.1构build

 class ViewController: UICollectionViewController { var values = ["tortile", "jetty", "tisane", "glaucia", "formic", "agile", "eider", "rooter", "nowhence", "hydrus", "outdo", "godsend", "tinkler", "lipscomb", "hamlet", "unbreeched", "fischer", "beastings", "bravely", "bosky", "ridgefield", "sunfast", "karol", "loudmouth", "liam", "zunyite", "kneepad", "ashburn", "lowness", "wencher", "bedwards", "guaira", "afeared", "hermon", "dormered", "uhde", "rusher", "allyou", "potluck", "campshed", "reeda", "bayonne", "preclose", "luncheon", "untombed", "northern", "gjukung", "bratticed", "zeugma", "raker"] @IBOutlet weak var flowLayout: UICollectionViewFlowLayout! override func viewDidLoad() { super.viewDidLoad() flowLayout.estimatedItemSize = CGSize(width: 10, height: 10) } override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return values.count } override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! MyCell cell.name = values[indexPath.row] return cell } override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { values.removeAtIndex(indexPath.row) collectionView.deleteItemsAtIndexPaths([indexPath]) } } class MyCell: UICollectionViewCell { @IBOutlet weak var label: UILabel! var name: String? { didSet { label.text = name } } } 

当从集合视图中删除单元格时,所有剩余的单元格将animation到其estimatedItemSize ,然后交换回正确的大小。

在这里输入图像说明

有趣的是,当animation发生时,这会为每个单元格产生自动布局约束警告:

 2015-12-02 14:30:45.236 CollectionTest[1631:427853] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSAutoresizingMaskLayoutConstraint:0x14556f780 h=--& v=--& H:[UIView:0x1456ac6c0(10)]>", "<NSLayoutConstraint:0x1456acfd0 UIView:0x1456ac6c0.trailingMargin == UILabel:0x1456ac830'raker'.trailing>", "<NSLayoutConstraint:0x1456ad020 UILabel:0x1456ac830'raker'.leading == UIView:0x1456ac6c0.leadingMargin>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x1456acfd0 UIView:0x1456ac6c0.trailingMargin == UILabel:0x1456ac830'raker'.trailing> 

我最初的想法是,打破这些限制是造成resize问题的原因。

更新单元的awakeFromNib方法:

 override func awakeFromNib() { super.awakeFromNib() contentView.translatesAutoresizingMaskIntoConstraints = false } 

修复了警告,但问题仍然存在。

我尝试在单元格和contentView之间重新添加自己的约束,但是这并没有解决问题:

 override func awakeFromNib() { super.awakeFromNib() contentView.translatesAutoresizingMaskIntoConstraints = false for constraint in [ contentView.leadingAnchor.constraintEqualToAnchor(leadingAnchor), contentView.trailingAnchor.constraintEqualToAnchor(trailingAnchor), contentView.topAnchor.constraintEqualToAnchor(topAnchor), contentView.bottomAnchor.constraintEqualToAnchor(bottomAnchor)] { constraint.priority = 999 constraint.active = true } } 

思考?

stream布局按照估计的尺寸进行布局,计算单元的实际尺寸,以确定哪些尺寸可见。 之后,根据实际尺寸调整布局。

但是当它animation的时候,当它计算出animation的初始位置时,它并没有达到出列单元格的位置,并在那里运行自动布局,所以它只使用估计的大小。

最简单的方法是尝试给出最接近的估计大小,或者如果您可以在sizeForItemAt调用的委托中提供大小。

在我的情况下,我试图animationlayoutAttributes,而不插入或删除单元格,对于具体情况,我subclassed UICollectionViewFlowLayout ,然后重写此方法:

 override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) { if !context.invalidateEverything && context.invalidatedItemIndexPaths == nil && context.contentOffsetAdjustment == .zero && context.contentSizeAdjustment == .zero { return } super.invalidateLayout(with: context) } 

这可防止在没有任何更改时使用估计大小重新计算布局属性。