UICollectionViewCells 在重新排列后正在重置它们的大小

Posted

技术标签:

【中文标题】UICollectionViewCells 在重新排列后正在重置它们的大小【英文标题】:UICollectionViewCells are resetting their size after being rearranged 【发布时间】:2015-01-02 14:41:38 【问题描述】:

我有一个带有标签的单元格 UICollectionView,我希望能够通过拖放对它们重新排序。

单元格的大小使用estimatedItemSize,因为我希望它们都是不同的大小,具体取决于单元格中文本的大小。我可以让它看起来很好。但是,一旦我使用 collectionView.moveItemAtIndexPath,单元格似乎会诉诸默认大小。

在移动后立即重置 collectionView 的流布局也不能解决问题。

viewDidLoad

    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.estimatedItemSize = CGSize(width: 100, height: 100)
    collectionView.collectionViewLayout = layout

重新排序文本的 UIPanGestureRecognizer

func handlePan(sender: UIPanGestureRecognizer) 
    let locationPoint = sender.locationInView(collectionView)
    if sender.state == UIGestureRecognizerState.Began 

        if let indexPath = collectionView.indexPathForItemAtPoint(locationPoint)? 

            if let cell = collectionView.cellForItemAtIndexPath(indexPath) 
                UIGraphicsBeginImageContext(cell.bounds.size)
                cell.layer.renderInContext(UIGraphicsGetCurrentContext())
                let cellImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()

                movingCellImage = UIImageView(image: cellImage)
                movingCellImage.center = locationPoint
                movingCellImage.transform = CGAffineTransformMakeScale(2, 2)
                collectionView.addSubview(movingCellImage)
                cell.alpha = 0
                movingCellOriginalIndexPath = indexPath

            

        

     else if sender.state == UIGestureRecognizerState.Changed 
        movingCellImage.center = locationPoint

     else if sender.state == UIGestureRecognizerState.Ended 

        if let indexPath = collectionView.indexPathForItemAtPoint(locationPoint)? 

            let cell = collectionView.cellForItemAtIndexPath(movingCellOriginalIndexPath)
            collectionView.moveItemAtIndexPath(movingCellOriginalIndexPath, toIndexPath: indexPath)
            cell?.alpha = 1

        

        movingCellImage.removeFromSuperview()
    

【问题讨论】:

Storyboards 中靠近 UILabel 底部的属性称为“Autoresize Subviews”。如果我没记错的话,这会让 UILabel 调用“sizeToFit”,这似乎是你的问题。这些都没有经过测试,所以我没有把它作为答案。因此,如果您关闭该选项,它可能会解决此问题 【参考方案1】:

使用动画重新加载似乎可以解决问题。但是之前的布局会暂时保留...您可能需要创建自定义 UICollectionViewLayout 而不是使用 estimatedSize

if let indexPath = collectionView.indexPathForItemAtPoint(locationPoint)? 
    let cell = collectionView.cellForItemAtIndexPath(movingCellOriginalIndexPath)
    collectionView.moveItemAtIndexPath(movingCellOriginalIndexPath, toIndexPath: indexPath)
    cell?.alpha = 1

    collectionView.reloadSections(NSIndexSet(index: 0)) // not reloadData

[更新]

正如您所指出的,密钥是-collectionView:layout:sizeForItemAtIndexPath:

不要将estimatedSize 设置为UICollectionViewFlowLayout 在上面的委托方法中计算每个单元格的大小

像这样:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize 
    let str = data[indexPath.item] // string to show in label

    // calculate size. you can use -boundingRectWithSize: as well
    var txtsize = (str as NSString).sizeWithAttributes([ NSFontAttributeName : UIFont.systemFontOfSize(16)]) // specify label's font
    txtsize.width += 10 // add margin if necessary
    txtsize.height = 100 // calculated text height or any value you want

    return txtsize

【讨论】:

调用 reloadSections 确实将单元格恢复为具有估计大小的小/紧版本。感谢那。不过你是对的,以前的布局会短暂出现并且看起来很糟糕。你知道一种方法可以使用 UICollectionViewLayout sizeForItemAtIndexPath 来为每个不同的文本设置不同的高度和宽度吗? 这个更新似乎可以解决我所有的问题,但是我遇到了 txtsize 返回的问题。例如,单词“all”给出了 NaN 的宽度。如果我强制 str 为“HELLO”,则宽度仅为 6.953,这是在边距之后。也许我错过了什么? 您指定哪种字体来计算字符串大小?字体(和大小)应与标签相同。在我的环境中,“all”的大小(无边距)是(16.032,19.088),“HELLO”是(51.84,19.088),systemFont(16pt)。 我正在使用您的代码,并且已让我在 IB 中的单元格使用您在代码中指定的相同系统大小 16。我已经在两个不同的 collectionViews 中尝试过它(尽管都在同一个项目中)。在 IB 中,标签简单说“标签”,并且使用自动布局,从顶部、右侧、底部和左侧开始 10。这可能是保持宽度在 2.21 左右和高度在 6.9 左右的原因吗? 我无法重现您的问题...所以我上传了测试项目here。请下载并运行。

以上是关于UICollectionViewCells 在重新排列后正在重置它们的大小的主要内容,如果未能解决你的问题,请参考以下文章

在横向上消失的 UICollectionViewCells

UICollectionView 在 UICollectionViewCells 上调用 setNeedsDisplay

UICollectionViewCells 中的 CABasicAnimation 在屏幕外完成

如何在 UICollectionView 中的 UICollectionViewCells 之间添加视图?

在 Swift 4 中居中 UICollectionViewCells

在滚动期间重用 UICollectionViewCells