简体   繁体   English

自定义 UIView 上的 IntrinsicContentSize 拉伸内容

[英]IntrinsicContentSize on a custom UIView streches the content

I would like to create a custom UIView which uses/offers a IntrinsicContentSize, since its height depends on its content (just like a label where the height depends on the text).我想创建一个使用/提供 IntrinsicContentSize 的自定义UIView ,因为它的高度取决于其内容(就像高度取决于文本的 label 一样)。

While I found a lot of information on how to work with IntrinsicContentSize offered by existing Views, I found just a few bits on how to use IntrinsicContentSize on a custom 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()
    }
}
  • The initial high is set to 50初始高点设置为50

  • The draw methods draws a gray rect with a size 25 draw方法绘制一个大小为25的灰色矩形

  • height is changed to 300 and invalidateIntrinsicContentSize() is called高度更改为300并调用invalidateIntrinsicContentSize()

  • Placing a MyView instance in InterfaceBuilder works without any problem.在 InterfaceBuilder 中放置一个MyView实例没有任何问题。 The view does not need a height constraint视图不需要高度约束

However, in IB the initial height of 50 is used.但是,在 IB 中,使用了50的初始高度。 Why?为什么? IB draws the gray rect, thus the draw method is called. IB 绘制灰色矩形,因此调用draw方法。 So why is the height not changed to 300?那么为什么高度没有改为300呢?

What is also strange: When setting a background color it is drawn as well, also super.draw(...) is not called.还有什么奇怪的:当设置背景颜色时,它也被绘制,也没有调用super.draw(...) Is this intended?这是故意的吗?

I would expect a view with height of 300 and a gray rect at the top with a height of 25 .我期望一个高度为300的视图和一个高度为25的灰色矩形。 However, when running the project in simulator the result is different:但是,在模拟器中运行项目时,结果是不同的:

  • height of the view = 300 - OK视图的高度 = 300 - OK
  • height of content (= gray rect) = 150 (half view height) - NOT OK内容高度(= 灰色矩形)= 150(半视图高度) -不正常

It seems that the content was stretched from its original height of 25 to keep its relative height to the view.似乎内容从其原始高度25被拉伸以保持其与视图的相对高度。 Why is this?为什么是这样?

在此处输入图像描述

Trying to change the view's height from inside draw() is probably a really bad idea.尝试从draw()内部更改视图的高度可能是一个非常糟糕的主意。

First, as you've seen, changing the intrinsic content size does not trigger a redraw.首先,正如您所见,更改内在内容大小不会触发重绘。 Second, if it did, your code would go into an infinite recursion loop.其次,如果是这样,您的代码将 go 进入无限递归循环。

Take a look at this edit to your class:看看对 class 的编辑:

@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()
    }
}

Now, when you change the intrinsic height in IB via the IBDesignable property, it will update in your Storyboard properly.现在,当您通过IBDesignable属性更改 IB 中的固有高度时,它将在您的 Storyboard 中正确更新。

Here's a quick look at using it at run-time.下面是在运行时使用它的快速浏览。 Each tap (anywhere) will increase the height property by 50 (until we get over 300, when it will be reset to 50), which then invalidates the intrinsic content size and forces a call to draw() :每次点击(任何地方)都会将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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM