【问题标题】:IntrinsicContentSize on a custom UIView streches the content自定义 UIView 上的 IntrinsicContentSize 拉伸内容
【发布时间】:2021-08-27 16:40:54
【问题描述】:

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

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

@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 的灰色矩形

  • 高度更改为300 并调用invalidateIntrinsicContentSize()

  • 在 InterfaceBuilder 中放置 MyView 实例没有任何问题。视图不需要高度限制

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

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

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

  • 视图高度 = 300 - 确定
  • 内容高度(= 灰色矩形)= 150(半视图高度) - 不行

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

【问题讨论】:

    标签: ios uiview autolayout intrinsic-content-size


    【解决方案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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-20
      • 2018-04-28
      • 1970-01-01
      • 1970-01-01
      • 2013-12-13
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多