Swift - 如何根据其内部的UILabel大小调整UIView的大小

4
我在Swift方面还有些新手,需要一些帮助:
我有一个UIView内部的UILabel,这个标签可以接收任意数量的文本。因此,我想根据它接收到的文本调整UILabel的大小,并调整其容器UIView的大小。UILabel必须具有最大宽度但没有最大高度。这与WhatsApp中消息文本的情况非常相似(绿色容器会根据内部文本而增长)。
我认为这与自动布局有关,但我真的不太理解大部分内容。
编辑:动态创建。
有人能帮帮我吗?

UIView和Label是通过StoryBoard添加还是通过编写代码添加的?有人尝试过编写代码吗? - iOS Geek
Label继承自UIView,所以就是这样。或者只需将UIView设置为标签的宽度(您可以在Storyboard中完成此操作)。 - stevenpcurtis
只有通过代码,它就像一场聊天。 - LeMag
4个回答

9
包含标签的UIView不应具有固定高度。只需添加约束以设置UIView宽度和X/Y坐标。
在其中,UILabel应具有固定的Top/Bottom和Right/Left约束,还要将其numberOfLines设置为0。
使用这些约束,容器视图将根据文本调整高度而扩展。
请参见附加的屏幕截图。
添加容器视图约束(注意没有添加底部或高度约束)
添加标签约束(固定约束到所有UIView边缘)

Label Constraints (fixed constraints to all UIView Edges)

短文本的结果

Result with short text

长文本的结果

Result with long text


如果视图和标签的大小开始较小(约30px),并且视图的宽度也必须增加,直到其宽度达到约300px,具体取决于标签的文本?我将动态创建所有这些内容,但是如果您使用IB进行说明,那也没有问题。 - LeMag
我需要以编程方式完成这个任务,因为我必须传递一个CGRect。我的视图已经被左右约束,但我需要传递高度。 - Hedylove

0
在编程中,使用标签放在容器视图内的时候有几种情况。
如果标签是容器的唯一子视图,你只需要将其约束到容器的边界上,并将标签的contentCompressionResistancePrioritycontentHuggingPriority都设置为required。如果这样做了,就不需要指定高度;高度将随着标签的增长而增长。
class LabelContainerView: UIView {
    
    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonSetup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonSetup()
    }
    
    func commonSetup() {
        addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.setContentHuggingPriority(.required, for: .vertical)
        label.setContentCompressionResistancePriority(.required, for: .vertical)
        label.text = "Hello, World."
        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: leadingAnchor),
            label.topAnchor.constraint(equalTo: topAnchor),
            label.trailingAnchor.constraint(equalTo: trailingAnchor),
            label.bottomAnchor.constraint(equalTo: bottomAnchor)
        
        ])
    }
    
}

如果你想在标签周围添加一些填充,你可以将其限制为父视图的layoutMarginsGuide,并额外调整layoutMargins以扩展/收缩填充。

NSLayoutConstraint.activate([
    label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
    label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
    label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
    label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
])

// Uncomment for more padding
//layoutMargins = .init(top: 40, left: 40, bottom: 40, right: 40)

然而,如果您在容器内有一个额外的视图(例如自定义背景视图),则需要告诉自动布局使用标签的intrinsicContentSize


 @IBDesignable
 class ContainerView: UIView {
     
     let customBackgroundView = CustomBackgroundView()
     let label = UILabel()
     
     override var intrinsicContentSize: CGSize {
         label.intrinsicContentSize // <-- Here
     }

     override init(frame: CGRect) {
         super.init(frame: frame)
         commonSetup()
     }
     
     required init?(coder: NSCoder) {
         super.init(coder: coder)
         commonSetup()
     }
     
     func commonSetup() {
         addSubview(customBackgroundView)
         addSubview(label)
         customBackgroundView.translatesAutoresizingMaskIntoConstraints = false
         label.translatesAutoresizingMaskIntoConstraints = false
         label.setContentHuggingPriority(.required, for: .vertical)
         label.setContentCompressionResistancePriority(.required, for: .vertical)
         label.text = "Hello, World."
         NSLayoutConstraint.activate([
             customBackgroundView.leadingAnchor.constraint(equalTo: leadingAnchor),
             customBackgroundView.topAnchor.constraint(equalTo: topAnchor),
             customBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor),
             customBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor),
             label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
             label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
             label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
             label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
         
         ])
     }
     
 }


class CustomBackgroundView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonSetup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonSetup()
    }
    
    func commonSetup() {
        backgroundColor = .clear
    }
    
    override func draw(_ rect: CGRect) {
        let path = UIBezierPath(rect: bounds)
        UIColor.red.setStroke()
        path.stroke()
    }
    
}


很多时候,自动布局的歧义可以通过使用intrinsicContentSize来解决。这为布局引擎提供了必要的提示,以计算其内部视图的大小。
如果一个视图只有固有的高度而没有宽度(或反之亦然),则始终使用常量UIView.noIntrinsicMetric来表示未定义的维度。
override var intrinsicContentSize: CGSize { 
    .init(width: UIView.noIntrinsicMetric, height: 42)
}
  

0

@Lefteris的回答是正确的。不需要定义包含视图的宽度和高度。您只需要将其约束在其父边缘中,然后在包含视图的边缘中约束标签。

这是我在代码中的做法。

let containingView: UIView = UIView()
containingView.translateAutoresizingMaskIntoConstraints = false
addSubview(containingView)

let labelInside: UILabel = UILabel()
labelInside.translateAutoresizingMaskIntoConstraints = false
containingView.addSubview(labelInside)

NSLayoutConstraint.activate([
  //in my case, i want my containingView on the top left corner of the superView.
   containingView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
   containingView.topAnchor.constraint(equalTo: contentView.topAnchor),

   labelInside.leadingAnchor.constraint(equalTo: containingView.leadingAnchor),
   labelInside.trailingAnchor.constraint(equalTo: containingView.trailingAnchor),
   labelInside.topAnchor.constraint(equalTo: containingView.topAnchor),
   labelInside.bottomAnchor.constraint(equalTo: containingView.bottomAnchor)
])

现在如果你想在标签中添加一些边距/插图,只需要在定义约束时添加一个常量即可。 :) 希望对你有帮助。


-2

以下属性对我有效,希望这可以帮到你

 [label sizeToFit];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接