替代sizeWithFont:ForWidth:lineBreakMode:方法的方案

5

许多我以前用于确定打印字符串布局以创建复杂的pdf文档的方法在iOS7中已被弃用。文档指出同一个方法可用作所有被弃用的sizeWithFont方法的替代品:

boundingRectWithSize:options:attributes:

对于sizeWithFont:ConstrainedTosize:lineBreakMode来说这很好,但如果我只想要我的字符串在一行上呢?我不知道最大高度应该用什么值,所以我没有一个矩形可以作为第一个参数的值。

下面是当限制大小时我的代码:

CGFloat maxHeightAllowable = _maxHeight;
CGSize issueTitleMaxSize = CGSizeMake(_issueListTitleColWidth - (kColumnMargin *2), maxHeightAllowable);
NSDictionary *issueTitleAttributes = [NSDictionary dictionaryWithObjectsAndKeys:_bodyFont, NSFontAttributeName, nil];
CGRect issueTitleRect = CGRectIntegral([issueTitleText boundingRectWithSize:issueTitleMaxSize options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:issueTitleAttributes context:nil]);
CGSize issueTitleSize = issueTitleRect.size;

我该如何使用相同的方法,如果我不知道 maxHeight,或者实际上,我正试图找出一行的高度?
我明白他们为什么会推动 NSAttributed 字符串和自动布局的兼容性,但为什么要将这些标记为弃用?在我的情况下,替代方案现在需要 4 或 5 个步骤,而以前只需要 1 或 2 步。
根据 T 先生建议的 lineHeight 属性,我在类别中制作了这些方法,大大简化了我的替换过程。
#import "NSString+SizingForPDF.h"

@implementation NSString (SizingForPDF)

-(CGSize)integralSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)maxSize
{
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
    CGRect rect = CGRectIntegral([self boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:attributes context:nil]);
    return rect.size;
}

-(CGSize)integralSizeWithFont:(UIFont *)font maxWidth:(CGFloat)maxWidth numberOfLines:(NSInteger)lines
{
    if (lines == 0) {
        lines = 1;
    }
    NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
    CGFloat height = font.lineHeight * lines;
    CGSize maxsize = CGSizeMake(maxWidth, height);
    CGRect rect = CGRectIntegral([self boundingRectWithSize:maxsize options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading attributes:attributes context:nil]);
    return rect.size;
}

@end
1个回答

15

如果您只是想查找一行的高度,那么您可以使用字体的lineHeight属性吗?我使用它来设置标签的高度或正确预测元素的高度而没有任何问题。我不确定在这方面PDF文档是否不同。

此外,我认为那些函数被弃用是因为NSString + UIKit函数系列(sizeWithFont:...等)是基于UIStringDrawing库开发的,后者不是线程安全的。如果你尝试在非主线程上运行它们(就像其他UIKit功能一样),你会得到不可预测的行为。特别是,如果你在多个线程上同时运行该函数,它可能会导致应用程序崩溃。这就是为什么在iOS 6中,他们引入了一个NSAttributedStrings的boundingRectWithSize: ...方法。这是基于NSStringDrawing库构建的,并且是线程安全的。

在这方面,如果您仅支持iOS 6和iOS 7,则我肯定会将所有NSString的sizeWithFont:...更改为NSAttributeString的boundingRectWithSize。如果您碰巧有奇怪的多线程角落情况,它将为您节省很多麻烦!以下是我如何转换NSString的sizeWithFont:constrainedToSize:

过去的做法是:

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

可以轻松地替换为:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
    [[NSAttributedString alloc]
        initWithString:text
        attributes:@
        {
            NSFontAttributeName: font
        }];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){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);

你的方法和我的差不多,只是我使用CGRectIntegral宏将值夹紧到整数。我从未想过要查看字体以获取行高。这对我来说就是答案。我用它在一个类别中创建了几个新方法,更容易地替换我的旧代码。 - Dean Davids
1
LineBreakMode已被替换为NSParagraphStyle属性,该属性可以添加到属性字典中。请参阅http://stackoverflow.com/a/26894770/338468以了解如何执行此操作的详细示例。 - Robert Altman

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