设置集合视图单元格的动态宽度时出现问题

Posted

技术标签:

【中文标题】设置集合视图单元格的动态宽度时出现问题【英文标题】:issue while set dynamic width of collection view cell 【发布时间】:2019-02-04 07:33:07 【问题描述】:

我正在尝试动态设置集合视图单元格的宽度。最初它没有按预期呈现。但是当我点击单元格时,它会根据我的需要进行调整。这是我写的代码:

代码

import UIKit

class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource 

    @IBOutlet weak var collView: UICollectionView!


    var tasksArray = ["To Do", "SHOPPING","WORK"]
    var selectedIndex = Int()

    override func viewDidLoad() 
        super.viewDidLoad()
        let layout = collView?.collectionViewLayout as! UICollectionViewFlowLayout
        layout.itemSize = UICollectionViewFlowLayout.automaticSize
        layout.estimatedItemSize = CGSize(width: 93, height: 40)
        // Do any additional setup after loading the view, typically from a nib.
    
    func numberOfSections(in collectionView: UICollectionView) -> Int 
        return 1
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return tasksArray.count
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
        cell.lblName.text = tasksArray[indexPath.row]
        if selectedIndex == indexPath.row
        
            cell.backgroundColor = UIColor.lightGray
        
        else
        
            cell.backgroundColor = UIColor.white
        
        cell.layer.borderWidth = 1
        cell.layer.cornerRadius = cell.frame.height / 2
        return cell
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
        selectedIndex = indexPath.row
        self.collView.reloadData()
    

这里我附上两张点击前和点击后的图片,以便您轻松理解

[![这是我点击之前的图像

单元格]2]2

所以请告诉我我的代码有什么问题

【问题讨论】:

请适当添加图片。我编辑了您的问题以解释问题。 【参考方案1】:

在您的 CollectionViewCell 覆盖 preferredLayoutAttributesFitting 函数中,这是单元格有机会指示其首选属性的地方,包括我们使用自动布局计算的大小。

 override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes 
    setNeedsLayout()
    layoutIfNeeded()
    let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
    var frame = layoutAttributes.frame
    frame.size.width = ceil(size.width)
    layoutAttributes.frame = frame
    return layoutAttributes

【讨论】:

【参考方案2】:

我发现了 swift 4.2 的一个小技巧

对于动态宽度和固定高度:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    let label = UILabel(frame: CGRect.zero)
    label.text = textArray[indexPath.item]
    label.sizeToFit()
    return CGSize(width: label.frame.width, height: 32)

【讨论】:

我不建议使用 sizeToFit。相应地设置约束。 你能告诉我我必须给出哪个约束【参考方案3】:

很明显,您必须使用sizeForItemAt 流布局委托才能传递动态宽度。但棘手的部分是根据文本计算单元格的宽度。给定字体,您实际上可以计算文本的宽度。

让我们介绍一些对我们有帮助的扩展

StringExtensions.swift

extension String 

    public func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat 
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constraintRect,
                                        options: .usesLineFragmentOrigin,
                                        attributes: [.font: font], context: nil)

        return ceil(boundingBox.width)
    

这个方法让我们知道一个字符串的宽度,如果我提供它的高度和字体。然后在sizeForItem里面使用如下

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    let height = 40
    let text = YOUR_TEXT
    let width = text.width(withConstrainedHeight: height, font: Font.regular.withSize(.extraSmall)) + EXTRA_SPACES_FOR_LEFT_RIGHT_PADDING
    return CGSize(width: width, height: height)

【讨论】:

以上是关于设置集合视图单元格的动态宽度时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

垂直放置集合视图单元格而不是水平放置?

更改集合视图中每个第三个单元格的宽度

如何在布局转换期间为集合视图单元格的边框宽度/颜色设置动画?

设置表格视图单元格的动态高度

集合视图中单元格的宽度不正确

集合视图单元格中的动态按钮宽度