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

B.S*_*.S. 5 objective-c nsstring uilabel ios

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

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

Rob*_*Rob 9

答案的核心是Cupcake的引用帖子.无论如何,您可以使用sizeWithFont:constrainedToSize:lineBreakMode:在给定特定自动换行的给定宽度的标签中找出框架的大小与特定字体的大小,例如

CGSize size = [string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:UILineBreakModeWordWrap];
Run Code Online (Sandbox Code Playgroud)

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

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

无论哪种方式,这个迭代计算的大小可以是相当cpu密集的操作,所以要小心.

更新:

这是一个算法,NSStringUILabel使用默认字体返回可以适应问题的长度(但忽略最小字体大小):

- (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];
}
Run Code Online (Sandbox Code Playgroud)

例如,如果你检查了单词分解模式,跳转到下一个单词分隔符然后调用sizeWithFont,你可能会提高效率,但对于小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];
}
Run Code Online (Sandbox Code Playgroud)

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

  • 此方法现已弃用,因此您可以使用 - (CGRect)boundingRectWithSize:(CGSize)大小选项:(NSStringDrawingOptions)options context:(NSStringDrawingContext*)context NS_AVAILABLE_IOS(6_0); 代替 (3认同)