【问题标题】:With what should I replace the deprecated sizeWithFont: method?我应该用什么替换已弃用的 sizeWithFont: 方法?
【发布时间】:2013-08-21 08:19:17
【问题描述】:

我有一个方法可以给我一个完美的 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) 为什么去掉这个方法?是因为和这个其他方法有重叠吗?

【问题讨论】:

  • 参考这个link

标签: objective-c nsstring deprecated


【解决方案1】:

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

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);

【讨论】:

  • 谢谢你。我现在为 iOS6 使用类似的东西,它使用您创建的 stringAttributes 字典创建一个 NSAttributedString,并在属性字符串上调用 boundingRectWithSize:options:context:。
  • 比你!真的很有用!
【解决方案2】:

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

如果您查看新的 NSString boundingRectWithSize:... 函数,它会以与 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);

【讨论】:

  • 没有解决换行模式问题
【解决方案3】:

换行问题:

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

【讨论】:

    【解决方案4】:

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

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-06
      • 2021-12-30
      相关资源
      最近更新 更多