sizeWithFont方法已经被弃用。boundingRectWithSize返回了一个意外的值。

83
在iOS7中,sizeWithFont已被废弃,所以我正在使用boundingRectWithSize(它返回一个CGRect值). 我的代码:
 UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

 CGSize maximumLabelSize = CGSizeMake(310, 9999);

 CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                             options:NSStringDrawingUsesLineFragmentOrigin
                             attributes:@{NSFontAttributeName:fontText}
                             context:nil];

 expectedLabelSize = CGSizeMake(textRect.size.width, textRect.size.height);

textRect中,我得到的尺寸比我的maximumLabelSize要大,与使用sizeWithFont时的尺寸不同。我该如何解决这个问题?


我遇到了所有字体的问题,不仅是系统字体或Helvetica。 - Nirav Jain
你有任何想法如何做到这一点吗? - Nirav Jain
具体的字体名称、文本和不匹配的大小的示例可能会有所帮助。 - Eiko
我也遇到了同样的问题,最好使用TT。 - Sri..
但是这里有开发人员给出了很好的答案,我考虑并且正在正常工作。 - Nirav Jain
显示剩余2条评论
6个回答

152

那么创建一个新的标签,然后使用sizeThatFit:(CGSize)size如何?

UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:@"YOUR FONT's NAME" size:16];
gettingSizeLabel.text = @"YOUR LABEL's TEXT";
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);

CGSize expectSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

编辑:上面的代码在 iOS 7 及以上版本中不好用,因此请使用下面的代码:

CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                         options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingUsesFontLeading
                         attributes:@{NSFontAttributeName:fontText}
                         context:nil];

当我在字符串中添加HTML实体(如<OL>,<LI>)时,此方法无法正常工作。 - Nirav Jain
请再检查一下我的答案!我错过了numberOfLines属性!抱歉! - Quang Hà
1
经过数小时的搜索、实验和死胡同,这是适用于iOS7和Xamarin / Monotouch的唯一可行解决方案。 - Michael Rodrigues
26
创建一个用于计算字体大小的标签?太浪费资源了! - Ossir
13
@Ossir,你有更好的想法吗? - Luda
显示剩余2条评论

37

或许您需要为这个答案中建议的方法提供额外的选项:

CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                                         options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                      attributes:@{NSFontAttributeName: fontText}
                                         context:nil];

3
看起来boundingRectWithSize有问题。我在iOS 7、7.1.1上进行了测试,结果并不正确。 - Rafał Sroka
这对我没有起作用,但是在NSAttributedString上使用boundingRectWithSize,并将我的字体属性添加到字符串中确实起作用了。 - Sheepdogsheep
12
伙计们,不要忘记苹果公司的声明:在iOS 7及更高版本中,此方法返回分数大小(在返回的CGRect的大小组件中); 要使用返回的大小来调整视图的大小,必须使用 ceil 函数将其值提升到最近的较高整数。 - SoftDesigner
2
ceil 对我来说不够用,但是发现使用 ceil 并加上 0.5 就解决了问题。 - dwery

15

这是我的工作代码片段:

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:attributeDict];

NSString *headline  = [dict objectForKey:@"title"];  
UIFont *font        = [UIFont boldSystemFontOfSize:18];  
CGRect  rect        = [headline boundingRectWithSize:CGSizeMake(300, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];

CGFloat height      = roundf(rect.size.height +4)

我将计算出的高度增加了4个像素,因为如果没有这4个像素,会少一行。

我在tableView中使用这段代码,并将“height”添加到NSNumber数组中,可以得到默认textLabel的正确单元格高度。

如果您想在textLabel下方获得更多的空间,请再添加4个像素。

**** 更新 ****

我不同意“宽度40像素的错误”,应该是缺失高度的4个像素,因为4个像素是单行字母与边界之间的默认高度。

您可以通过一个UILabel进行检查,对于字体大小为16,需要UILabel高度为20。

但是,如果您的最后一行没有“g”或其他字符,测量可能会缺少4个像素的高度。

我用一个小方法重新检查了一下,我的标签可以准确地获得20、40或60的高度和小于300px的正确宽度。

为了支持iOS6和iOS7,您可以使用我的方法:

- (CGFloat)heightFromString:(NSString*)text withFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    float iosVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (iosVersion >= 7.0) {
        rect = [text boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
        CGSize size = [text sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
    }
    NSLog(@"%@: W: %.f, H: %.f", self, rect.size.width, rect.size.height);
    return rect.size.height;
}

**** 升级 ****

感谢您的评论,我按照以下方式升级了我的功能。由于sizeWithFont已经被弃用,在XCode中会得到警告,因此我添加了诊断-预处理器指令来消除这个特定函数调用/代码块的警告。

- (CGFloat)heightFromStringWithFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        rect = [self boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        CGSize size = [self sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
#pragma GCC diagnostic pop
    }
    return ceil(rect.size.height);
}

除了4像素的话题之外: 根据您使用的字体和字重,计算返回不同的高度值。在我的情况下:HelveticaNeue-Medium字体,字号为16.0,在单行中返回20.0的行高,但在两行中返回39.0,在4行时为78px-->每行缺少1像素-从第2行开始-但是如果要让您的字体大小+ 4px的行距作用于每一行,则必须获得一个高度结果。
编码时请记住这一点!
我还没有针对这个“问题”的函数,但完成后我会更新此帖子。


1
你应该使用[text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]而不是检查浮点值。 - Samah
1
最好使用 ceil 函数而不是 +4pt,可以看看这个答案:https://dev59.com/z2ct5IYBdhLWcg3wc9Ag#23563152 - surfrider

2

@SoftDesigner的评论对我有用

CGRect descriptionRect = [description boundingRectWithSize:CGSizeMake(width, 0)
                                                       options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}
                                                       context:nil];
result = ceil(descriptionRect.size.height);

2
如果我理解正确,您正在使用boundingRectWithSize:作为获取使用sizeWithFont获得的大小的一种方法(意思是您直接想要CGSize,而不是CGRect)?
这看起来像是您正在寻找的: iOS 7中已弃用的sizeWithFont:的替代品? 他们使用sizeWithAttributes:来获取大小,作为sizeWithFont的替代品。
您是否仍然会使用类似以下内容的错误大小:
UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

expectedLabelSize = [myString sizeWithAttributes:@{NSFontAttributeName:fontText}];

但是我该如何使用CGSize maximumLabelSize = CGSizeMake(310, 9999)?我需要正确的高度和宽度。 - Nirav Jain
1
有没有任何属性可以告诉 sizeWithAttributes: 限制它的宽度/高度? - Nirav Jain
抱歉,但我不明白你的问题是什么。如果我理解正确,你想根据字体大小调整标签的尺寸,但不超过最大高度。你说你以前可以使用sizeWithFont方法实现这个功能,但现在这个方法已经被弃用了,对吗?你应该能够以与之前使用sizeWithFont相同的方式使用sizeWithAttributes方法。在你使用sizeWithFont时,你是如何限制标签的尺寸的?你能贴出使用sizeWithFont时对你有效的代码吗? - vinaut
2
他正在使用sizeWithFont:constrainedToSize:lineBreakMode:,但是无法将constrainedToSize的值传递给sizeWithAttributes。 - zh.

1

为了在运行时找到标签的大小,iOS 7.0不再使用sizewithfont方法,而是要使用-boundingRectWithSize:options:attributes:context:方法。

您可以像下面的代码一样使用它:

CGSize constraint = CGSizeMake(MAXIMUM_WIDHT, TEMP_HEIGHT);
NSRange range = NSMakeRange(0, [[self.message body] length]);

NSDictionary *attributes = [YOUR_LABEL.attributedText attributesAtIndex:0 effectiveRange:&range];
CGSize boundingBox = [myString boundingRectWithSize:constraint options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
int numberOfLine = ceil((boundingBox.width) / YOUR_LABEL.frame.size.width);
CGSize descSize = CGSizeMake(ceil(boundingBox.width), ceil(self.lblMessageDetail.frame.size.height*numberOfLine));

CGRect frame=YOUR_LABEL.frame;
frame.size.height=descSize.height;
YOUR_LABEL.frame=frame;

在这里,您需要为找到高度或宽度给出最大长度的宽度。

尝试一下,对我有用。


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