39
[self.Review sizeToFit];

sizeToFit 之前的结果:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {198, 63}}

sizeToFit 后的结果:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {181, 45}}

我希望宽度保持不变。我只是想改变高度。自动遮罩是

(lldb) po self.Review
(UILabel *) $1 = 0x08bb0fe0 <UILabel: 0x8bb0fe0; frame = (90 20; 181 45); text = 'I'm at Mal Taman Anggrek ...'; clipsToBounds = YES; opaque = NO; autoresize = LM+RM+H; userInteractionEnabled = NO; layer = <CALayer: 0x8bb68b0>>

我知道有一种方法可以做到这一点: 如何调整 UILabel 的宽度并使其适合文本大小?

答案要么很奇怪(我们需要重新提供字体信息)。或者不清楚。

您还需要定义最大宽度,并告诉您的程序如果 sizeToFit 为您提供的宽度大于该最大值时该怎么做。

我将使用 using 的奇怪解决方案sizeWithFont。这很奇怪,因为 UILabel 已经知道标签中的字体。

实际上 sizeToFit 的行为如何?它如何决定我们需要更薄还是更高的 UILabel?

4

10 回答 10

44

您可以使用 sizeThatFits 获得相同的结果。

CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)];
CGRect frame = label.frame;
frame.size.height = size.height;
label.frame = frame;

或者,使用 sizeToFit。

CGRect frame = label.frame;
[label sizeToFit];
frame.size.height = label.frame.size.height;
label.frame = frame;
于 2013-01-23T11:11:06.103 回答
41

这就是它的完成方式。因为标签已经包含字体信息,所以在这个方法调用中包含它是微不足道的。

CGSize size = [label.text sizeWithFont:label.font
                     constrainedToSize:CGSizeMake(maxWidth, MAXFLOAT)
                         lineBreakMode:UILineBreakModeWordWrap]; 
CGRect labelFrame = label.frame;
labelFrame.size.height = size.height;
label.frame = labelFrame;

使用更新的 Swift 版本boundingRectWithSize

let maxHeight = CGFloat.infinity
let rect = label.attributedText?.boundingRectWithSize(CGSizeMake(maxWidth, maxHeight), 
       options: .UsesLineFragmentOrigin, context: nil)
var frame = label.frame
frame.size.height = rect.size.height
label.frame = frame
于 2012-10-25T12:23:08.100 回答
17

sizeToFit 效果很好。唯一的问题是它基于控件的当前大小。

例如,如果您正在回收带有标签的表格视图单元格,则标签的宽度可能已在前一个单元格中减小,因此对 sizeToFit 的调用可能看起来不可靠。

只需在发送 sizeToFit 消息之前重置控件的原始宽度。

于 2013-12-12T13:52:27.337 回答
5

Swift 3 这个问题的简单扩展。

extension UILabel {
    func sizeToFitHeight() {
        let size: CGSize = self.sizeThatFits(CGSize.init(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
        var frame:CGRect = self.frame
        frame.size.height = size.height
        self.frame = frame
    }
}
于 2017-03-09T04:55:31.787 回答
2

我认为你不应该使用NSString'ssize...方法,UILabel正如@vatrif 指出的那样,已经有一个 API (内部可能只使用NSString's 方法)。

不过我认为UILabel's API 可以改进。这就是为什么我认为类别将是最优雅的解决方案:

//  UILabel+Resize.h
@interface UILabel (Resize)
- (void)sizeToFitHeight;
@end

//  UILabel+Resize.m
@implementation UILabel (Resize)
- (void)sizeToFitHeight {
    CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
    CGRect frame = self.frame;
    frame.size.height = size.height;
    self.frame = frame;
}
@end

只有一件事:我不确定该方法的适当名称:

  • sizeToFitHeight?
  • 高度适合?

非常感谢评论,谢谢!

于 2014-05-15T23:35:03.507 回答
2

同意的 API 将从这一添加中受益。让您的生活更轻松,并为 Swift 中的 UILabel 类添加扩展,如下所示:

extension UILabel {

    func sizeToFitHeight() {
        let size:CGSize = self.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max))
        var frame:CGRect = self.frame
        frame.size.height = size.height
        self.frame = frame
    }
}
于 2016-03-16T15:54:58.970 回答
2

回答2017...

c = CGSize(width: yourWidth, height: CGFloat.greatestFiniteMagnitude)
结果 = sizeThatFits(c).height

所以...

let t = .... your UITextView
let w = .... your known width of the item

let trueHeight = t.sizeThatFits(
                   CGSize(width: t, height: CGFloat.greatestFiniteMagnitude)).height

就是这样。


很多时候,您想知道与“正常”单行条目相比的高度差异

如果您正在制作某种与 UTableView 无关的单元格(例如,某种自定义堆栈视图),则尤其会出现这种情况。您必须在某些时候手动设置高度。在您的故事板上,使用任何短字符串(例如“A”)的示例文本按照您的意愿构建它,在任何正常情况下当然只有一行。然后你做这样的事情......

func setTextWithSizeCorrection() { // an affaire iOS

    let t = .... your UITextView
    let w = .... your known width of the item

    let oneLineExample = "A"
    let actualText = yourDataSource[row].description.whatever
    
    // get the height as if with only one line...
    
    experimental.text = oneLineExample
    let oneLineHeight = t.sizeThatFits(
               CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height
    
    // get the height with the actual long text...
    // (note that usually, you do not want a one-line minimum)
    
    experimental.text = (actualText == "") ? oneLineExample : actualText
    let neededHeight = t.sizeThatFits(
              CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height
    
    experimental.text = actualText
    
    let delta = neededHeight - oneLineHeight
    
    set the height of your cell, or whatever it is(standardHeight + delta)
}

最后一点:iOS 中真正愚蠢的事情之一是 UITextView 内部有一种奇怪的边距。这意味着您不能只在 UITextViews 和标签之间进行交换;它会导致许多其他问题。截至撰写本文时,Apple 尚未解决此问题。解决这个问题很困难:以下方法通常是可以的:

@IBDesignable class UITextViewFixed: UITextView {
    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }
    func setup() {
        textContainerInset = UIEdgeInsets.zero;
        textContainer.lineFragmentPadding = 0;
    }
}

来自Apple的破碎,无法使用的UITextView......

在此处输入图像描述

UITextViewFixed在大多数情况下,这是一个可以接受的修复:

在此处输入图像描述

(为清楚起见,添加了黄色。)

于 2017-02-19T22:07:35.230 回答
1

SWIFT 3 的固定解决方案

用于CGFloat.greatestFiniteMagnitude最大高度。

let size = CGSize.init(width: yourLabel.frame.size.width,
                       height: CGFloat.greatestFiniteMagnitude)
let rect = errorLabel.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
var frame = errorLabel.frame
frame.size.height = (rect?.size.height)!
errorLabel.frame = frame


或创建UIlabel扩展,并调用方法yourLabel. sizeToFitHeight()

extension UILabel {

    func sizeToFitHeight() {
        let maxHeight : CGFloat = CGFloat.greatestFiniteMagnitude
        let size = CGSize.init(width: self.frame.size.width, height: maxHeight)
        let rect = self.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
        var frame = self.frame
        frame.size.height = (rect?.size.height)!
        self.frame = frame
    }

} 
于 2017-02-11T13:36:06.450 回答
1

我相信我有一个更简单的解决方案:

let oldWidth = self.frame.size.width
label.sizeToFit()
label.frame.size.width = oldWidth

只需存储旧的宽度,sizeToFit()适用于宽度和高度,然后将宽度重置回原来的值,只改变标签的高度。

于 2019-10-17T00:02:54.937 回答
0

Swift 3 版本的Mundi的回答:

let maxHeight: CGFloat = 10000
let rect = label.attributedText!.boundingRect(with: CGSize(width: maxWidth, height: maxHeight),
                                                           options: .usesLineFragmentOrigin,
                                                           context: nil)
var frame = labe.frame
frame.size.height = rect.size.height
label.frame = frame
于 2016-12-16T02:59:01.813 回答