5

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

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

4

1 回答 1

11

答案的核心在 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,但对于 small UILabels 这可能就足够了。如果您想利用自动换行逻辑来最小化您调用的次数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];
}

也许这里使用的字符集不太正确(例如,您是否应该包括连字符),但如果您不需要这样做,它可能非常接近并且比逐个字符更有效。

于 2012-06-22T14:40:45.690 回答