0

我创建了一个自定义视图,该视图MyIntrincView在设置其内容时自动计算其高度。这在模拟器和 InterfaceBuilder 中都可以正常工作。

但是,当放置MyIntrinsicView在 a中时UITableViewCell,单元格高度计算正确。所有单元格都保持相同的初始高度,而不是自动将单元格高度应用于视图的固有高度。

// A simple, custom view with intrinsic height. The height depends on
// the value of someProperty. When the property is changed setNeedsLayout
// is set and the height changes automatically.
@IBDesignable class MyIntrinsicView: UIView {
    @IBInspectable public var someProperty: Int = 5 {
        didSet { setNeedsLayout() }
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        calcContent()
    }
    
    func calcContent() {
        height = CGFloat(20 * someProperty)
        invalidateIntrinsicContentSize()
    }
    
    
    @IBInspectable var height: CGFloat = 50
    override var intrinsicContentSize: CGSize {
        return CGSize(width: super.intrinsicContentSize.width, height: height)
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        invalidateIntrinsicContentSize()
    }
}


// A simple cell which only contains a MyIntrinsicView subview. The view
// is attached to trailing, leading, top and bottom anchors of the cell.
// Thus the cell height should automatically match the height of the
// MyIntrinsicView
class MyIntrinsicCell: UITableViewCell {
    @IBOutlet private var myIntrinsicView: MyIntrinsicView!
    
    var someProperty: Int {
        get { return myIntrinsicView.someProperty }
        set {
            myIntrinsicView.someProperty = newValue
            
            // Cell DOES NOT rezise without manualle calling layoutSubviews()
            myIntrinsicView.layoutSubviews()
        }
    }
}

...
// Simple tableView delegate which should create cells of different heights 
// by giving each cell a different someProperty 
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "IntrinsicCell", for: indexPath) as? MyIntrinsicCell ?? MyIntrinsicCell()
    
    // Give all cell a different intrinsic height by setting someProperty to rowIndex
    cell.someProperty = indexPath.row
    return cell
}

我希望每个单元格都有不同的高度(20 * someProperty= 20 * indexPath.row)。但是,所有单元格都具有相同的初始高度。

仅当显式调用myIntrinsicView.layoutSubviews()单元格时,才会创建具有正确高度的单元格。

似乎 tableView 没有调用myIntrinsicView.layoutSubviews(). 为什么是这样?

当使用具有不同文本长度UILabelMyIntrinsicView单元格内容时,一切都按预期工作。因此,整个 tableView 设置是正确的(= 单元格大小是自动计算的),并且必须有办法正确使用内在大小UITableView那么,这样做的正确方法到底是什么?

4

1 回答 1

0

与您之前的问题一样我认为您并没有真正理解做什么intrinsicContentSize和不做什么。

设置 a 的文本时UILabel,是的,它intrinsicContentSize会发生变化,但这还不是全部。

您也不想做您正在尝试的事情layoutSubviews()......如果您的代码确实触发了更改,您将进入无限递归循环(再次,与您之前的问题一样)。

看看对您的代码的修改:

// A simple, custom view with intrinsic height. The height depends on
// the value of someProperty. When the property is changed setNeedsLayout
// is set and the height changes automatically.
@IBDesignable class MyIntrinsicView: UIView {
    @IBInspectable public var someProperty: Int = 5 {
        didSet {
            calcContent()
            setNeedsLayout()
        }
    }
    
    func calcContent() {
        height = CGFloat(20 * someProperty)
        invalidateIntrinsicContentSize()
    }
    
    
    @IBInspectable var height: CGFloat = 50
    override var intrinsicContentSize: CGSize {
        return CGSize(width: super.intrinsicContentSize.width, height: height)
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        invalidateIntrinsicContentSize()
    }
}


// A simple cell which only contains a MyIntrinsicView subview. The view
// is attached to trailing, leading, top and bottom anchors of the cell.
// Thus the cell height should automatically match the height of the
// MyIntrinsicView
class MyIntrinsicCell: UITableViewCell {
    @IBOutlet private var myIntrinsicView: MyIntrinsicView!
    
    var someProperty: Int {
        get { return myIntrinsicView.someProperty }
        set {
            myIntrinsicView.someProperty = newValue
        }
    }
}

两个旁注...

1 - 您发布的代码显示您myIntrinsicView.layoutSubviews()从 Apple 的文档中调用 ...:

您不应直接调用此方法。如果要强制更新布局,请在下一次绘图更新之前调用 setNeedsLayout 方法。如果您想立即更新视图的布局,请调用 layoutIfNeeded 方法。

2 - 对于看起来像你前进的方向,你可能会更好地操纵约束常数,而不是内在的内容大小。

于 2021-06-11T16:17:39.540 回答