如何知道NSString是否适合UILabel以及最后一个适合的字符串的索引?

时间:2012-06-22 12:02:59

标签: objective-c ios nsstring uilabel

我有4行UILabel,具有精确的框架和字体。

我需要知道这个字符串是否适合标签,以及最后一个字符的索引是什么。

1 个答案:

答案 0 :(得分:9)

答案的核心是Cupcake的引用帖子。无论如何,您可以使用sizeWithFont:constrainedToSize:lineBreakMode:来确定给定特定自动换行的给定宽度的标签中的特定字体的帧大小。

CGSize size = [string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:UILineBreakModeWordWrap];

sizeConstraint设置为与标签相同的宽度,但将高度设置为更大。如果生成的size.height大于您的UILabel,那么您的字符串太长。从理论上讲,你可以删除最后一个字符/单词,然后再试一次,直到它适合。

如果您认为字符串可能很长,您可能想要另一种方式,从字符串的一小部分开始并继续添加字符直到它太大,然后您知道最后一个字符。

无论哪种方式,这个迭代计算的大小都可以进行cpu密集操作,所以要小心。

<强>更新

这是一种算法,它使用默认字体(但忽略最小字体大小)返回可以容纳到NSString中的UILabel的长度:

- (NSUInteger)fitString:(NSString *)string intoLabel:(UILabel *)label
{
    UIFont *font           = label.font;
    UILineBreakMode mode   = label.lineBreakMode;

    CGFloat labelWidth     = label.frame.size.width;
    CGFloat labelHeight    = label.frame.size.height;
    CGSize  sizeConstraint = CGSizeMake(labelWidth, CGFLOAT_MAX);

    if ([string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height > labelHeight) 
    {
        NSString *adjustedString;

        for (NSUInteger i = 1; i < [string length]; i++) 
        {
            adjustedString = [string substringToIndex:i];

            if ([adjustedString sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height > labelHeight)
                return i - 1;
        }
    }

    return [string length];
}

例如,如果您检查了分词模式,跳转到下一个单词分隔符然后调用sizeWithFont,那么您可能会提高效率,但对于小UILabel s,这可能就足够了。如果您想利用自动换行逻辑来最小化调用sizeWithFont的次数,您可能会有以下内容:

- (NSUInteger)fitString:(NSString *)string intoLabel:(UILabel *)label
{
    UIFont *font           = label.font;
    UILineBreakMode mode   = label.lineBreakMode;

    CGFloat labelWidth     = label.frame.size.width;
    CGFloat labelHeight    = label.frame.size.height;
    CGSize  sizeConstraint = CGSizeMake(labelWidth, CGFLOAT_MAX);

    if ([string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height > labelHeight) 
    {
        NSUInteger index = 0;
        NSUInteger prev;
        NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];

        do 
        {
            prev = index;
            if (mode == UILineBreakModeCharacterWrap)
                index++;
            else
                index = [string rangeOfCharacterFromSet:characterSet options:0 range:NSMakeRange(index + 1, [string length] - index - 1)].location;
        }
        while (index != NSNotFound && index < [string length] && [[string substringToIndex:index] sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height <= labelHeight);

        return prev;
    }

    return [string length];
}

这里使用的字符集可能不太正确(例如,如果你包括连字符),但它可能非常接近并且比逐字符更有效,如果你不需要这样做的话。 / p>