代码之家  ›  专栏  ›  技术社区  ›  ByteSlinger

如何通过编程调整UILabel上的宽度和高度?

  •  0
  • ByteSlinger  · 技术社区  · 7 年前

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

    内置的 sizeToFit UILabel方法对于单行UILabels非常有效,但对于多行文本,它会正确设置高度,但宽度设置得太小,导致较长的文本行换行。

    在用户输入文本之前,我不知道标签的宽度。我想调整标签的大小以适应最长文本行的宽度。根据@DonMag的评论,我还想限制标签的宽度不超过屏幕。

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

    我已经搜索了很多相关的解决方案,但是没有一个能解决尺寸适合宽度和高度的问题。

    有没有办法以编程方式调整多行UILabel的大小,使其既适合文本的宽度又适合文本的高度?

    2 回复  |  直到 7 年前
        1
  •  0
  •   DonMag    7 年前

    你可以这样做 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项目已更新。。。现在包括两个手动帧设置的示例 自动布局/约束。

        2
  •  0
  •   ByteSlinger    7 年前

    通过更多的实验,我发现了一些我还没见过的伎俩。一般来说,它是这样工作的:

    • 查找最长的文本行
    • 将numberOfLines设置为1(临时)
    • 将标签文本设置为最长文本行
    • Call label.sizeToFit(设置最长行的标签宽度)
    • 将numberOfLines设置为0(多行)
    • 将标签文本设置为完整的多行文本
    • Call 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];
    }