如何在 Swift 中动态更改包含 UICollectionView 单元格的 UITableView 单元格的高度?

Posted

技术标签:

【中文标题】如何在 Swift 中动态更改包含 UICollectionView 单元格的 UITableView 单元格的高度?【英文标题】:How to dynamically change the height of a UITableView Cell containing a UICollectionView cell in Swift? 【发布时间】:2017-07-18 20:46:40 【问题描述】:

目前,我已在 UITableViewCellUITableView 的一个部分中嵌入了 UICollectionViewCell。我知道如何在UITableView 的另一部分动态更改单元格的高度,因为我在另一个UITableViewCell 中有一个UITextView,它根据UITextView 中的文本量动态更改单元格的高度。

我遇到的问题是关于包含UICollectionViewCellUITableViewCell。我的UICollectionViewCell 有一行 4 张图片,用户可以使用 UIImagePickerController 通过相机或照片库添加这些图片。

目前据我所知,当生成第五张图片时,UITableViewCell 的高度保持不变,但用户可以像这样在UICollectionViewCell 中水平滚动:

我的最终目标是这样的

还有我的故事板:

非常不言自明,但如果只有 4 张图片,UITableViewCell 与屏幕截图 1 中的相同,但如果 UICollectionViewCell 的高度发生变化,单元格的高度将动态变化。

我已将UICollectionView 的滚动方向设置为仅垂直。在进一步解释之前,这是我的部分代码:

class TestViewController: UITableViewController, UITextFieldDelegate, UITextViewDelegate, UIImagePickerControllerDelegate

    override func viewDidLoad()
    
        super.viewDidLoad()

        ....

        tableView.estimatedRowHeight = 40.0
        tableView.rowHeight = UITableViewAutomaticDimension

    

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

    
        var cell: UITableViewCell = UITableViewCell()

        if indexPath.section == 1
        
            cell = tableView.dequeueReusableCell(withIdentifier: "TextViewCell", for: indexPath)

            let textView: UITextView = UITextView()

            textView.isScrollEnabled = false

            textView.delegate = self
            cell.contentView.addSubview(textView)
        
        else if indexPath.section == 4
        
            if let imagesCell = tableView.dequeueReusableCell(withIdentifier: "ImagesCell", for: indexPath) as? CustomCollectionViewCell
            
                if images_ARRAY.isEmpty == false
                
                    imagesCell.images_ARRAY = images_ARRAY
                    imagesCell.awakeFromNib()
                

                return imagesCell
            

        

        return cell
    

    ....

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
    
        if indexPath.section == 1
        
            return UITableViewAutomaticDimension
        
        else if indexPath.section == 4
        
            //return 95.0
            return UITableViewAutomaticDimension
        

        return 43.0
    

    ....

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
    
        if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
        
            if let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 4) ) as? CustomCollectionViewCell
            
                cell.images_ARRAY.append(selectedImage)
                cell.imagesCollectionView.reloadData()
            
        
        picker.dismiss(animated: true, completion: nil)
    

    ....

    func textViewDidChange(_ textView: UITextView)
    
        ...
        // Change cell height dynamically
        tableView.beginUpdates()
        tableView.endUpdates()
    


class CustomCollectionViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout

    @IBOutlet var imagesCollectionView: UICollectionView!

    var images_ARRAY = [UIImage]()

    var images = [INSPhotoViewable]()

    override func awakeFromNib()
    
        super.awakeFromNib()

        for image in images_ARRAY
        
            images.append(INSPhoto(image: image, thumbnailImage: image) )
        

        imagesCollectionView.dataSource = self
        imagesCollectionView.delegate = self
    

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int

    
        return images_ARRAY.count
    

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

    
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! ExampleCollectionViewCell

        cell.populateWithPhoto(images[(indexPath as NSIndexPath).row]

        return cell
    

    ....

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
    
        return UIEdgeInsetsMake(0.0, 25.0, 0.0, 25.0)
    

最初,包含UICollectionViewCellindexPath.section == 4 返回高度95,但我将其注释掉并将其替换为返回UITableViewAutomaticDimension。我假设调整了单元格的高度以适合第 5 张图像,但即使 UICollectionViewCell' 高度发生变化,单元格仍保持静态高度,允许我在该静态 UITableViewCell 高度内垂直滚动。

我知道这些是我发现的一些与我的情况非常相似的问题,但它们并没有帮助我解决我的特定问题:

    Swift: Expand UITableViewCell height depending on the size of the UICollectionView inside it Auto Height of UICollectionView inside UITableViewCell UICollectionView inside a UITableViewCell — dynamic height?

根据一些答案和建议,我添加了以下内容:

imagesCell.images_ARRAY = images_ARRAY
imagesCell.awakeFromNib()

// Added code
imagesCell.frame = tableView.bounds
tableView.setNeedsLayout()
tableView.layoutIfNeeded()

但是,这没有任何影响。谁能指出我需要哪些代码并放置在哪里的正确方向?

谢谢!

【问题讨论】:

【参考方案1】:

我在我的代码中使用了这些类型的单元格,性能并不出色(因为会影响滚动平滑度),但可以让您实现所需的设计。

    在tableViewCell 中使用CollectionView,垂直滚动方向和固定宽度(我的意思是本质上不是动态的)。这将在填充水平方向后将溢出的单元格放在垂直方向。 从 collectionViewHeight 的 xib(如果你正在使用它)中取出 NSLayoutConstraint。我们将在后面使用它。 在 tableView 中的 heightForRowAtIndexPath 方法中设置 UITableViewAutomaticDimension。 最后使用我们在步骤 2 中取出的约束在 cellForRowAtIndexPath 方法中返回单元格时设置单元格的 collectionViewHeight。

我在这里附上一些可能会有所帮助的代码:

UITableView 部分:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return UITableViewAutomaticDimension


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: xyzTableViewCell.self), for: indexPath) as! xyzTableViewCell
    cell.collectionViewHeight.constant = (numberOfCells/5) * cell.cellHeight
    return cell

UITableViewCell 部分:

@IBOutlet fileprivate weak var collectionView: UICollectionView!
@IBOutlet weak var collectionViewHeight: NSLayoutConstraint

并且您将需要重新加载该特定 tableViewCell 并在此 tableViewCell 中重新加载 collectionView 以便调用 tableView 的高度函数并刷新该 tableViewCell 的高度,并处理该 tableViewCell 的聚焦条件(当 tableViewCell 处于焦点时),我这样说是因为如果它不在焦点中(或者说缓存,它们之间存在差异),那么在滚动时将调用 cellForRowAtIndexPath 方法(当这个单元格将成为焦点时)然后 tableViewCell 高度将已经被占用照顾。

希望这将有助于实现所需的功能。

【讨论】:

以上是关于如何在 Swift 中动态更改包含 UICollectionView 单元格的 UITableView 单元格的高度?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 swift 中的按钮点击动态更改 textview 中的字体?

Swift:当节标题高度动态更改时,UITableView 滚动回顶部

UITableView:单击按钮时如何动态更改单元格高度?迅速

如何在swift4中动态添加滚动视图

如何在 Swift 中的 Spritkit 中制作动态位置

如何在 swift 中单击按钮时更改 uiimage 的图像?