如何使一个自定义的视图的框架匹配其内容禀大小 [英] How to make a custom view's frame match its instrinsic content size

查看:190
本文介绍了如何使一个自定义的视图的框架匹配其内容禀大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在做一个从无到有的标签。 (我的最终目的是使蒙古文字竖排文本标签,但现在我只是做一个正常的水平文本标签的做法。)

I'm making a label from scratch. (My end purpose is to make a vertical text label for Mongolian script, but for now I am just making a normal horizontal text label as practice.)

只要没有长度和宽度的限制,我希望我的自定义标签的框架,以根据其内在的内容大小调整。

As long as there are no length and width constraints, I want my custom label's frame to resize according to its intrinsic content size.

在IB一切似乎当我测试是工作的罚款的UILabel ,我的自定义标签(A 的UIView 子),以及一个按钮。

In IB everything seems to be working fine when I test a UILabel, my custom label (a UIView subclass), and a button.

我添加顶部和约束领导到每个这些意见,但没有设置任何高度或宽度的限制。

I add top and leading constrains to each of these views but don't set any height or width constraints.

在这里输入的形象描述

如果我调整他们的故事板(但仍然不添加任何更多的限制)...

If I resize them on the storyboard (but still without adding any more constraints)...

在这里输入的形象描述

然后再选择的更新帧的对的在View控制器的,正常的标签各方意见,我的自定义标签都妥善调整它们的内在内容的大小。

And then choose Update Frames for All Views in View Controller, the normal label and my custom label both resize properly to their intrinsic content sizes.

在这里输入的形象描述

当我在运行时更改标签文本,不过,我的自定义标签的框架是不调整。 (我暂时增加了一个深蓝色的边框文字层,以帮助从自定义标签的框架,这是淡蓝色背景色在这里区别开来。)

When I change the label text at runtime, though, my custom label's frame is not resizing. (I temporarily added a dark blue border to the text layer to help differentiate it here from the custom label's frame, which is the light blue background color.)

在这里输入的形象描述

单击更改文本给

在这里输入的形象描述

正如你所看到,文本层帧改变,但自定义视图的框架没有。

As you can see, the text layer frame changed but the custom view's frame didn't.

这是我的自定义标签类:

This is my custom label class:

import UIKit
@IBDesignable
class UILabelFromScratch: UIView {

    private let textLayer = CATextLayer()

    @IBInspectable var text: String = "" {
        didSet {
            updateTextLayerFrame()
        }
    }

    @IBInspectable var fontSize: CGFloat = 17 {
        didSet {
            updateTextLayerFrame()
        }
    }

    // MARK: - Initialization

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    func setup() {

        // Text layer
        textLayer.borderColor = UIColor.blueColor().CGColor
        textLayer.borderWidth = 1
        textLayer.contentsScale = UIScreen.mainScreen().scale
        layer.addSublayer(textLayer)
    }

    // MARK: Other methods

    override func intrinsicContentSize() -> CGSize {
        return textLayer.frame.size
    }

    func updateTextLayerFrame() {

        let myAttribute = [ NSFontAttributeName: UIFont.systemFontOfSize(fontSize) ]
        let attrString = NSMutableAttributedString(string: self.text, attributes: myAttribute )
        let size = dimensionsForAttributedString(attrString)

        textLayer.frame = CGRect(x: self.layer.bounds.origin.x, y: self.layer.bounds.origin.y, width: size.width, height: size.height)
        textLayer.string = attrString

    }

    func dimensionsForAttributedString(attrString: NSAttributedString) -> CGSize {

        var ascent: CGFloat = 0
        var descent: CGFloat = 0
        var width: CGFloat = 0
        let line: CTLineRef = CTLineCreateWithAttributedString(attrString)
        width = CGFloat(CTLineGetTypographicBounds(line, &ascent, &descent, nil))

        // make width an even integer for better graphics rendering
        width = ceil(width)
        if Int(width)%2 == 1 {
            width += 1.0
        }

        return CGSize(width: width, height: ceil(ascent+descent))
    }
}

这里是视图控制器类:

And here is the view controller class:

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var normalLabel: UILabel!
    @IBOutlet weak var labelFromScratch: UILabelFromScratch!

    @IBAction func changeTextButtonTapped(sender: UIButton) {

        normalLabel.text = "Hello"
        labelFromScratch.text = "Hello"
    }
}

问题

它是什么,的UILabel 确实,我在我的自定义标签很想念?我推翻 intrinsicContentSize

Question

What is it that UILabel does that I am missing in my custom label? I overrode intrinsicContentSize:

override func intrinsicContentSize() -> CGSize {
    return textLayer.frame.size
}

还有什么我需要做什么?

What else do I need to do?

推荐答案

我失踪了code一行:

I was missing a single line of code:

invalidateIntrinsicContentSize()

我更新文本层帧后增加了。

I added it after updating the text layer frame.

func updateTextLayerFrame() {

    // ...

    textLayer.frame = CGRect(x: self.layer.bounds.origin.x, y: self.layer.bounds.origin.y, width: size.width, height: size.height)
    invalidateIntrinsicContentSize()

    // ...
}

的<一个href=\"https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/index.html#//apple_ref/occ/instm/NSView/invalidateIntrinsicContentSize\"相对=nofollow>文档说:

调用此当事情在你的自定义视图将更改的失效
  其内在的内容大小。这使得基于约束的布局
  系统采取新的内在含量的大小考虑在其下
  布局传递。

Call this when something changes in your custom view that invalidates its intrinsic content size. This allows the constraint-based layout system to take the new intrinsic content size into account in its next layout pass.

在哪里,我发现这个解决方案:

Where I found this solution:

  • Advanced Auto Layout Toolbox

这篇关于如何使一个自定义的视图的框架匹配其内容禀大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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