如何根据其内容自动设置自定义UIView宽度?

时间:2018-09-24 12:58:16

标签: ios swift uiview autolayout

我有一个简单的自定义UIView(屏幕截图中带有白色背景的视图),它使用了xib和从UIView派生的自定义类。

Custom view

在内部,我只拥有一个UILabel和一个按钮,就可以了。

按钮的大小是固定的。 标签的宽度必须根据其内容进行调整。

我想要的是: -使标签的大小适合其内容 -始终在标签之后设置按钮的位置 -使自定义适合其内容

赞:

Correct Cutsom view

我该怎么做?

添加内容:

class Keyword: UIView {

@IBOutlet weak var label: UILabel!
@IBOutlet var contentView: UIView!

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

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

fileprivate func commonInit() {
    Bundle.main.loadNibNamed("Keyword", owner: self, options: nil)
    addSubview(contentView)
    contentView.frame = self.bounds
}

override var intrinsicContentSize: CGSize {
    let height = CGFloat(21)
    return CGSize(width: UIViewNoIntrinsicMetric, height: height)
}

/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
    // Drawing code
}
*/

}

UILabel约束:

UILabel contraints

勾选UIButton约束:

enter image description here

2 个答案:

答案 0 :(得分:0)

以下扩展名可用于计算标签的高度和宽度。

extension String {

//Calculate height and width for label with string
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
    let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
    let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

    return ceil(boundingBox.height)
}

func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
    let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
    let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

    return ceil(boundingBox.width)
}

}

在这种情况下,由于按钮大小是固定的,因此可以使用上述扩展名来计算标签的宽度,并且可以用于设置整个视图的宽度约束。如果标签的前导约束为8,按钮的尾随约束为8,而按钮的容器视图的尾随约束为8,则可以将视图的所需宽度计算为:

viewWidthConstraint.constant = 8+<width of string from the above extension>+8+<width of button>+8

这里唯一改变的参数将是标签的宽度。

答案 1 :(得分:0)

感谢@matt,我找到了解决方法。

我的代码中只有2个错误。

  1. 自定义视图中缺少以下行代码translatesAutoresizingMaskIntoConstraints = false,因此从未调用intrinsicContentSize
  2. 根据@matt的建议,在intrinsicContentSize内,我需要基于标签和按钮的固有宽度提供一个值作为宽度参数,而不是UIViewNoIntrinsicMetric

现在,正确的代码是:

class Keyword: UIView {

@IBOutlet weak var label: UILabel!
@IBOutlet weak var btn: UIButton!
@IBOutlet var contentView: UIView!

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

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

fileprivate func commonInit() {
    translatesAutoresizingMaskIntoConstraints = false
    Bundle.main.loadNibNamed("Keyword", owner: self, options: nil)
    addSubview(contentView)
    contentView.frame = self.bounds
}

override var intrinsicContentSize: CGSize {
    let height = btn.frame.size.height
    let width =  btn.frame.origin.x + btn.frame.size.width
    return CGSize(width: width, height: height)
}


// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
    // Drawing code
}

}