0

我正在以编程方式创建多行 UILabel ( [label setNumberOfLines:0];)。

UILabel的内置sizeToFit方法对 1 行 UILabel 效果很好,但对于多行文本,它设置了适当的高度,但宽度设置得太小,导致较长的文本行换行。

直到用户输入他们的文本后,我才知道标签宽度。我想调整标签的大小以适应最长文本行的宽度。根据@DonMag 的评论,我还想限制标签不比屏幕宽。

我尝试了不同的lineBreakMode设置,但没有“nowrap”选项。

我搜索了 SO 并且有很多相关的解决方案,但没有一个可以解决宽度和高度的 sizeToFit 问题。

有没有办法以编程方式调整多行 UILabel 的大小以适应文本的宽度和高度?

4

2 回答 2

0

你可以用boundingRectWithSize......

将您的标签添加到视图并给它一个起始宽度约束(什么值并不重要,因为它会被更改)。

保留对该宽度约束的引用(如果您使用的是 IB,则 IBOutlet 可以正常工作)。

不要给它高度限制。

当您设置标签的文本时,您可以使用它来更改其宽度:

// get the font of the label
UIFont *theFont = _theLabel.font;

// get the text of the label
NSString *theString = _theLabel.text;

// calculate the bounding rect, limiting the width to the width of the view
CGRect r = [theString boundingRectWithSize:CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX)
                                   options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                attributes:@{NSFontAttributeName: theFont}
                                   context:nil];

// change the constant of the constraint to the calculated width
_theWidthConstraint.constant = ceil(r.size.width);

// NOTE: If you are *not* using auto-layout, 
// this same calculation can be used to explicitly set
// the .frame of the label.

编辑:

根据 OP 的要求,一个完整的、可运行的示例——仅使用代码,没有故事板/IB——可以在这里找到:https ://github.com/DonMag/MultilineLabelFitWidth

编辑2:

GitHub 项目已更新...现在包括手动框架设置自动布局/约束的示例。

于 2018-08-02T18:58:49.967 回答
0

通过更多的实验,我发现了一些我在 SO(还......)中没有看到的技巧。一般来说,它是这样工作的:

  • 查找最长的文本行
  • 将 numberOfLines 设置为 1(暂时)
  • 将标签文本设置为最长的文本行
  • 调用 label.sizeToFit(设置最长线的标签宽度)
  • 将 numberOfLines 设置为 0(多行)
  • 将标签文本设置为完整的多行文本
  • 调用 label.sizeToFit(设置所有行的标签高度)

瞧!现在,您的 UILabel 已调整大小以适合您的多行文本。

这是一个示例(GitHub 上的演示项目:UILabelSizeToFitDemo):

- (UILabel *)label = nil;

- (void)updateLabel:(NSString *)notes {
    // close to the "sticky" notes color
    UIColor *bananaColor = [ViewController colorWithHexString:@"#FFFC79"];

    if (_label == nil) {
        _label = [[UILabel alloc] init];
        _label.numberOfLines = 0;
        _label.textColor = UIColor.blackColor;
        [_label setBackgroundColor:[bananaColor colorWithAlphaComponent:0.9f]];
        _label.textAlignment = NSTextAlignmentLeft;

        [self.view addSubview:_label];
    }

    // make font size based on screen size
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
    CGFloat fontSize = MIN(screenWidth,screenHeight) / 12;
    [_label setFont:[UIFont systemFontOfSize:fontSize]];

    // split lines
    NSArray *lines = [notes componentsSeparatedByString:@"\n"];
    NSString *longestLine = lines[0];   // prime it with 1st line

    // fill a temp UILabel with each line to find the longest line
    for (int i = 0; i < lines.count; i++) {
        NSString *line = (NSString *)lines[i];

        if (longestLine == nil || line.length > longestLine.length) {
            longestLine = line;
        }
    }

    // force UILabel to fit the largest line
    [_label setNumberOfLines:1];
    [_label setText:longestLine];
    [_label sizeToFit];

    // make sure it doesn't go off the screen
    if (_label.frame.size.width > screenWidth) {
        CGRect frame = _label.frame;
        frame.size.width = screenWidth - 20;
        _label.frame = frame;
    }
    // now fill with the actual notes (this saves the previous width)
    [_label setNumberOfLines:0];
    [_label setText:notes];
    [_label sizeToFit];


    // center the label in my view
    CGPoint center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2);
    [_label setCenter:center];
}

更新:这是一个替代的完整解决方案,使用boundinRectWithSize来自@DonMag 的代码片段:

-(void)updateLabel:(NSString *)notes {
    // close to the "sticky" notes color
    UIColor *bananaColor = [ViewController colorWithHexString:@"#FFFC79"];

    if (_label == nil) {
        _label = [[UILabel alloc] init];
        _label.numberOfLines = 0;
        _label.textColor = UIColor.blackColor;
        _label.backgroundColor = [bananaColor colorWithAlphaComponent:0.9f];
        _label.textAlignment = NSTextAlignmentLeft;

        [self.view addSubview:_label];
    }

    // set new text
    _label.text = notes;

    // make font size based on screen size
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
    CGFloat fontSize = MIN(screenWidth,screenHeight) / 12;
    [_label setFont:[UIFont systemFontOfSize:fontSize]];

    // calculate the bounding rect, limiting the width to the width of the view
    CGRect frame = [notes boundingRectWithSize:CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX)
                                       options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                    attributes:@{NSFontAttributeName: _label.font}
                                       context:nil];

    // set frame and then use sizeToFit
    [_label setFrame:frame];
    [_label sizeToFit];

    // center the label in my view
    CGPoint center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
    [_label setCenter:center];
}
于 2018-08-02T19:00:09.423 回答