0

我想创建一个UIView使用/提供 IntrinsicContentSize 的自定义,因为它的高度取决于其内容(就像高度取决于文本的标签一样)。

虽然我找到了很多关于如何使用现有视图提供的 IntrinsicContentSize 的信息,但我发现了一些关于如何在自定义上使用 IntrinsicContentSize 的信息UIView

@IBDesignable class MyIntrinsicView: UIView {
    override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(UIColor.gray.cgColor)
        context?.fill(CGRect(x: 0, y: 0, width: frame.width, height: 25))
        
        height = 300
        invalidateIntrinsicContentSize()
    }
    
    
    @IBInspectable var height: CGFloat = 50
    override var intrinsicContentSize: CGSize {
        return CGSize(width: super.intrinsicContentSize.width, height: height)
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        invalidateIntrinsicContentSize()
    }
}
  • 初始高点设置为50

  • 这些draw方法绘制一个大小为灰色的矩形25

  • 高度更改为300invalidateIntrinsicContentSize()称为

  • 在 InterfaceBuilder 中放置一个MyView实例没有任何问题。视图不需要高度约束

但是,在 IB 中使用初始高度50为什么?IB 绘制灰色矩形,因此该draw方法被调用。那么为什么高度没有改为300呢?

还有什么奇怪的:当设置背景颜色时,它也被绘制,也super.draw(...)没有被调用。这是故意的吗?

我希望有一个高度为 的视图,300顶部有一个高度为 的灰色矩形25。但是,在模拟器中运行项目时,结果是不同的:

  • 视图的高度 = 300-好的
  • 内容高度(= 灰色矩形)= 150(半视图高度) -不正常

似乎内容已从其原始高度拉伸,25以保持其与视图的相对高度。为什么是这样?

在此处输入图像描述

4

1 回答 1

1

试图从内部改变视图的高度draw()可能是一个非常糟糕的主意。

首先,正如您所见,更改内在内容大小不会触发重绘。其次,如果确实如此,您的代码将进入无限递归循环。

看看你的班级的这个编辑:

@IBDesignable class MyIntrinsicView: UIView {
    override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(UIColor.gray.cgColor)
        context?.fill(CGRect(x: 0, y: 0, width: frame.width, height: 25))

        // probably a really bad idea to do this inside draw()
        //height = 300
        //invalidateIntrinsicContentSize()
    }
    
    
    @IBInspectable var height: CGFloat = 50 {
        didSet {
            // call when height var is set
            invalidateIntrinsicContentSize()
            // we need to trigger draw()
            setNeedsDisplay()
        }
    }
    
    override var intrinsicContentSize: CGSize {
        return CGSize(width: super.intrinsicContentSize.width, height: height)
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        // not needed
        //invalidateIntrinsicContentSize()
    }
}

现在,当您通过IBDesignable属性更改 IB 中的固有高度时,它将在您的 Storyboard 中正确更新。

下面是在运行时使用它的快速浏览。每次点击(任何地方)都会将height属性增加 50(直到我们超过 300,然后它将被重置为 50),然后使内在内容大小无效并强制调用draw()

class QuickTestVC: UIViewController {
    
    @IBOutlet var testView: MyIntrinsicView!
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        var h: CGFloat = testView.intrinsicContentSize.height
        h += 50
        if h > 300 {
            h = 50
        }
        testView.height = h
    }
}
于 2021-06-10T17:22:06.950 回答