Search code examples
iosobjective-cuilabelnsattributedstring

Calculate the range of visible text in UILabel


I have an UILabel with fixed size, the text that I set into this UILabel can be 200, 5 or 500 characters long. What I want to do is to calculate how much visible text can I put into this UILabel with the current UILabel size.

Why I want to do that? Because I want to add a ...Read more text at the end of the text, but not at the end of the whole text, just at the end of the visible text in the UILabel.

Thanks in advance.


Solution

  • So I've created a method which returns the current visible string height (with the size of the UITextView / UITextField or UILabel) and it's also support iOS6+, this is what I did:

    - (NSUInteger)fitString:(NSString *)string intoLabel:(UILabel *)label
    {
        UIFont *font           = label.font;
        NSLineBreakMode mode   = label.lineBreakMode;
    
        CGFloat labelWidth     = label.frame.size.width;
        CGFloat labelHeight    = label.frame.size.height;
        CGSize  sizeConstraint = CGSizeMake(labelWidth, CGFLOAT_MAX);
    
        if (SYSTEM_VERSION_GREATER_THAN(iOS_7))
        {
            NSDictionary *attributes = @{ NSFontAttributeName : font };
            NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:string attributes:attributes];
            CGRect boundingRect = [attributedText boundingRectWithSize:sizeConstraint options:NSStringDrawingUsesLineFragmentOrigin context:nil];
            {
                if (boundingRect.size.height > labelHeight)
                {
                    NSUInteger index = 0;
                    NSUInteger prev;
                    NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    
                    do
                    {
                        prev = index;
                        if (mode == NSLineBreakByCharWrapping)
                            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] boundingRectWithSize:sizeConstraint options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size.height <= labelHeight);
    
                    return prev;
                }
            }
        }
        else
        {
            if ([string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height > labelHeight)
            {
                NSUInteger index = 0;
                NSUInteger prev;
                NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    
                do
                {
                    prev = index;
                    if (mode == NSLineBreakByCharWrapping)
                        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];
    }
    

    Of course that SYSTEM_VERSION_GREATER_THAN(iOS_7) are both macros that I defined. You also should define your own.

    Best of luck!