自定义 UIView 上的 IntrinsicContentSize 拉伸内容 [英] IntrinsicContentSize on a custom UIView streches the content

查看:65
本文介绍了自定义 UIView 上的 IntrinsicContentSize 拉伸内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 上使用 IntrinsicContentSize 的信息:

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:

@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

    The draw methods draws a gray rect with a size 25

    height 改为 300 并调用 invalidateIntrinsicContentSize()

    height is changed to 300 and invalidateIntrinsicContentSize() is called

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

    Placing a MyView instance in InterfaceBuilder works without any problem. The view does not need a height constraint

    然而,在 IB 中使用了 50 的初始高度.为什么? IB绘制灰色矩形,从而调用draw方法.那为什么高度没有改成300呢?

    However, in IB the initial height of 50 is used. Why? IB draws the gray rect, thus the draw method is called. So why is the height not changed to 300?

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

    What is also strange: When setting a background color it is drawn as well, also super.draw(...) is not called. Is this intended?

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

    I would expect a view with height of 300 and a gray rect at the top with a height of 25. However, when running the project in simulator the result is different:

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

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

    It seems that the content was stretched from its original height of 25 to keep its relative height to the view. Why is this?

    推荐答案

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

    Trying to change the view's height from inside draw() is probably a really bad idea.

    首先,如您所见,更改内在内容大小不会触发重绘.其次,如果是这样,您的代码将进入无限递归循环.

    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.

    看看这个对你的班级的

    @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 中正确更新.

    Now, when you change the intrinsic height in IB via the IBDesignable property, it will update in your Storyboard properly.

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

    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():

    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
        }
    }
    

    这篇关于自定义 UIView 上的 IntrinsicContentSize 拉伸内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆