如何在UILabel上以编程方式设置sizeToFit width AND height



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

UILabel的内置sizeToFit方法适用于1行UILabels,但对于多行文本,它正确设置了高度,但宽度设置得太小,导致较长的文本行换行。

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

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

我搜索过SO,有很多相关的解决方案,但没有一个能同时解决宽度和高度的sizeToFit问题。

有没有一种方法可以通过编程调整多行UILabel的大小,以适应文本的宽度和高度?

您可以使用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项目已更新。。。现在包括手动框架设置自动布局/约束的示例。

通过更多的实验,我发现了一些我在SO中还没有看到的东西

  • 查找最长的文本行
  • 将行数设置为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];
}

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

-(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];
}

最新更新