基于动态集合视图的UITableView的动态高度

时间:2019-01-04 11:45:57

标签: ios swift uitableview uicollectionview

我必须在UICollectionView内添加一个UITableViewCellcollectionView可以具有不同数量的项目。 因此,collectionView应该在tableView内部进行适当的调整。

我已经在我的项目中实现了这一点: https://github.com/vishalwaka/DynamicCollectionViewInsideTableViewCell

在我的情况下,设置collectionView的高度后未调整单元格的高度。

如何设置collectionView不可滚动,并同时显示tableviewcell内部的所有内容。

3 个答案:

答案 0 :(得分:2)

collectionView内创建一个UITableViewCell,其前导,尾随,顶部,底部,高度约束如下:

enter image description here

现在,在您的tableViewCell类中创建一个NSKeyValueObserver,并将其添加到UICollectionView contentSize 属性中,并将contentSize更改分配给collectionView的高度约束。 / p>

class FormCollectionTableViewCell: UITableViewCell{

  var collectionViewObserver: NSKeyValueObservation?

  override func awakeFromNib() {
    super.awakeFromNib()
    addObserver()
  }

  override func layoutSubviews() {
        super.layoutSubviews()
        layoutIfNeeded()
  }

  func addObserver() {
       collectionViewObserver = collectionView.observe(\.contentSize, changeHandler: { [weak self] (collectionView, change) in
            self?.collectionView.invalidateIntrinsicContentSize()
            self?.collectionViewHrightConstarint.constant = collectionView.contentSize.height
            self?.layoutIfNeeded()
        })
    }
   deinit {
      collectionViewObserver = nil
   }
}

在您的viewController类中,使用以下代码:

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        tableView.reloadData()
}

现在,您的表格视图将具有动态高度的集合视图。不要忘记禁用UICollectionView的滚动和调整其流量。

答案 1 :(得分:0)

创建collectionView的以下子类:

class IntrinsicSizeCollectionView: UICollectionView {

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.setup()
}

override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
    super.init(frame: frame, collectionViewLayout: layout)

    self.setup()
}

override func layoutSubviews() {
    super.layoutSubviews()
    if !self.bounds.size.equalTo(self.intrinsicContentSize) {
        self.invalidateIntrinsicContentSize()
    }
}

override var intrinsicContentSize: CGSize {
    get {
        let intrinsicContentSize = self.contentSize
        return intrinsicContentSize
    }
}

func setup() {
    self.isScrollEnabled = false
    self.bounces = false
}

将collectionView添加到tableViewCell并设置其约束,将其前后,顶部,底部限制为单元格的边界。还要按照屏幕截图所示设置固有尺寸。

enter image description here

tableViewCell的大小应设置为UITableViewAutomaticdimension,并且还应在TableView的dataSource中设置此单元格的估算高度。

那应该是全部。

答案 2 :(得分:0)

检查完项目后,我建议您使用稍微不同的方法。

更新模型后,您可以询问集合视图布局新的内容大小将是多少(collectionViewLayout.collectionViewContentSize)。然后,您更新高度约束常数。

因此,您应该:

  1. 更新您的模型
  2. 重新加载行
  3. 询问新psql: FATAL: password authentication failed for user "foo"的布局
  4. 更新高度约束常数

您的项目中的此修改应实现以下目的:

contentSize

请注意有关不需要任何其他布局更新调用的评论。只打电话  // Remove the content size observing logic. func configureForVehicle(_ vehicle: Vehicle, selectedHouseType: String) { self.vehicle = vehicle applianceCollectionView.reloadData() // Set the height constraint to the new value, found in the layout's content size info. // Since the model (self.vehicle) was already updated, the layout will return the new content size. // Because this is all happening while the cell is being reloaded, the cell will also resize properly. // You don't need to perform any other setNeedsLayout/layoutIfNeeded calls. self.applianceCollectionViewHeightConstraint.constant = applianceCollectionView.collectionViewLayout.collectionViewContentSize.height } 应该足够了。不必要的布局更新可能会导致性能下降。


请注意,如果您希望动画高度变化而不重新加载单元格,则可以使用另一种方法。在这种情况下,您需要保留/查找要更新的单元格的引用,然后执行以下操作:

  1. 在不调用任何表视图重载调用的情况下更新单元格的模型。
  2. 在更新后的单元格上重新加载集合视图。
  3. 以与上述相同的方式更新高度限制。
  4. 使用某种回调来通知表格视图单元格希望更新其高度。
  5. 在回调调用tableView.reloadRows(at: [indexPath], with: .automatic)中。这将导致tableView重新布局其单元并设置高度变化的动画。

来自beginUpdates() documentation

  

您还可以在不重新加载单元格的情况下,使用此方法以及endUpdates()方法为行高设置动画效果。这组方法必须以调用endUpdates()作为结束。