27

我有一个方法可以给我一个完美的 UITextView 大小给定字符串长度(具有相应的正确字体大小):

- (NSInteger) heightOfLabel:(NSString*) string {
    CGSize maximumLabelSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width - 40, FLT_MAX);
    CGSize expectedLabelSize = [[NSString stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:string]
             sizeWithFont:[UIFont systemFontOfSize:15]
             constrainedToSize:maximumLabelSize 
             lineBreakMode:NSLineBreakByWordWrapping];

    return expectedLabelSize.height + 5;
}

事实上,它仍然给了我一个完美的契合,即使在 iOS7 中。虽然现在它提出了一个警告方法,说我不应该使用'sizeWithFont:contrainedToSize:lineBreakMode'。

它现在说我应该使用 -boundingRectWithSize:options:attributes:context:

这种方法对 iOS7 来说并不新鲜,因此我认为可以在堆栈溢出时询问它,而不是去苹果官方开发者论坛。

我有三个问题:

1)因为它已被弃用,这是否意味着我一定要更换它,尽管它仍然有效?

2)我尝试了许多不同的 boundingRectWithSize: 方法,有各种变量,但它从来都不是完美的,它似乎总是有点过分(正如许多 stackoverflow 问题所指出的那样) - 是否有一个完美的替代品,这种不被弃用的方法完全可以和我以前的方法一样,麻烦最少?

3)为什么要删除这个方法?是因为与其他方法重叠吗?

4

4 回答 4

59

经过一个小时的试错后,我设法使它工作:

CGSize maximumLabelSize = CGSizeMake(tableView.width, MAXFLOAT);

NSStringDrawingOptions options = NSStringDrawingTruncatesLastVisibleLine |
                                 NSStringDrawingUsesLineFragmentOrigin;

NSDictionary *attr = @{NSFontAttributeName: [UIFont systemFontOfSize:15]};
CGRect labelBounds = [string boundingRectWithSize:maximumLabelSize 
                                          options:options
                                       attributes:attr
                                          context:nil];

更新:

正如 T 先生在下面的回答中提到的那样:在 iOS 7 及更高版本中,此方法返回小数大小(在返回的 CGRect 的大小组件中);要使用返回的大小来调整视图大小,您必须使用 ceil 函数将其值提高到最接近的更高整数。 ceilf推荐使用功能。

CGFloat height = ceilf(labelBounds.size.height);
于 2013-08-19T15:12:28.193 回答
14

我相信该函数已被弃用,因为该系列 NSString+UIKit 函数基于 UIStringDrawing 库,它不是线程安全的。如果您尝试不在主线程上运行它们(就像任何其他 UIKit 功能一样),您将获得不可预知的行为。特别是,如果您同时在多个线程上运行该函数,它可能会使您的应用程序崩溃。这就是为什么在 iOS 6 中,他们引入了boundingRectWithSize:...NSAttributedStrings 的方法。这是建立在 NSStringDrawing 库之上的,并且是线程安全的。

如果您查看新的 NSStringboundingRectWithSize:...函数,它会以与 NSAttributeString 相同的方式请求属性数组。如果我不得不猜测的话,iOS 7 中的这个新的 NSString 函数只是 iOS 6 中 NSAttributeString 函数的一个包装器。

关于这一点,如果您只支持 iOS 6 和 iOS 7,那么我肯定会将您的所有 NSString 更改sizeWithFont:...为 NSAttributeString boundingRectWithSize。如果您碰巧有一个奇怪的多线程角落案例,它将为您省去很多麻烦!这是我转换 NSString 的方法sizeWithFont:constrainedToSize:

曾经是什么:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font 
               constrainedToSize:CGSizeMake(width, CGFLOAT_MAX)];

可以替换为:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
    [[NSAttributedString alloc]
        initWithString:text
        attributes:@
        {
            NSFontAttributeName: font
        }];
CGRect rect = [attributedText boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;

请注意文档中提到:

在 iOS 7 及更高版本中,此方法返回小数大小(在返回的 CGRect 的大小组件中);要使用返回的大小来调整视图大小,您必须使用 ceil 函数将其值提高到最接近的更高整数。

因此,要提取用于调整视图大小的计算高度或宽度,我会使用:

CGFloat height = ceilf(size.height);
CGFloat width  = ceilf(size.width);
于 2013-09-23T03:26:44.127 回答
6

对于换行问题:

- (CGFloat)heightNeededForText:(NSString *)text withFont:(UIFont *)font width:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode {
    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = lineBreakMode;
    CGSize size = [text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                     options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                  attributes:@{ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle }
                                     context:nil].size;

    return ceilf(size.height);
}
于 2015-01-27T08:10:58.030 回答
3

挪威亚历山大的答案的斯威夫特版本......

func heightNeededForText(text: NSString, withFont font: UIFont, width: CGFloat, lineBreakMode:NSLineBreakMode) -> CGFloat {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineBreakMode = lineBreakMode
        let size: CGSize = text.boundingRectWithSize(CGSizeMake(width, CGFloat.max), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: [ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle], context: nil).size//text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MA

        return ceil(size.height);
    }

在要获取高度的代码中,只需调用如下方法...

let size = self.heightNeededForText(text as NSString, withFont: UIFont.systemFontOfSize(15.0), width: scrollView.frame.size.width - 20, lineBreakMode: NSLineBreakMode.ByWordWrapping) //Can edit the font size and LinebreakMode
于 2016-05-21T07:12:07.773 回答