12

Is there a way to get the visible part of text in word wrapped UILabel? I mean exactly the last visible character?

I'd like to make two labels rounding the image and would like to continue the text which was out of rect for first label on the second one.

I know [NSString sizeWithFont...] but are there something reversing like [NSString stringVisibleInRect: withFont:...] ? :-)

Thank you in advance.

Rajesh
  • 10,318
  • 16
  • 44
  • 64
Evgeny
  • 121
  • 1
  • 5

2 Answers2

7

You could use a category to extend NSString and create the method you mention

@interface NSString (visibleText)

- (NSString*)stringVisibleInRect:(CGRect)rect withFont:(UIFont*)font;

@end

@implementation NSString (visibleText)

- (NSString*)stringVisibleInRect:(CGRect)rect withFont:(UIFont*)font
{
    NSString *visibleString = @"";
    for (int i = 1; i <= self.length; i++)
    {
        NSString *testString = [self substringToIndex:i];
        CGSize stringSize = [testString sizeWithFont:font];
        if (stringSize.height > rect.size.height || stringSize.width > rect.size.width)
            break;

        visibleString = testString;
    }
    return visibleString;
}

@end
Vertism
  • 165
  • 6
  • 1
    Hi! Thanks, man. But it seems to me that this method with loop is too heavy. I'd like to find something native. – Evgeny Nov 07 '10 at 16:50
  • I'm not aware of a way to do this natively. Unless you will be calling this code a huge amount, I wouldn't imagine it would have any negative impact on your app. You could look at alloc and releasing all the string instances if you are really worried about memory usage. – Vertism Nov 08 '10 at 15:33
  • 1
    I'm not worrying about memory but just processor load. It seems that sizeWithFont should be really heavy and I was wonder is there any way to get, for instance, UILabel event when it crops some text away... That is my question was about :-) But it seems to me, that there is no solution. The only way is yours. – Evgeny Nov 08 '10 at 18:37
0

Here's a O(log n) method with iOS 7 APIs. Only superficially tested, please comment if you find any bugs.

- (NSRange)hp_visibleRange
{
    NSString *text = self.text;
    NSRange visibleRange = NSMakeRange(NSNotFound, 0);
    const NSInteger max = text.length - 1;
    if (max >= 0)
    {
        NSInteger next = max;
        const CGSize labelSize = self.bounds.size;
        const CGSize maxSize = CGSizeMake(labelSize.width, CGFLOAT_MAX);
        NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
        paragraphStyle.lineBreakMode = self.lineBreakMode;
        NSDictionary * attributes = @{NSFontAttributeName:self.font, NSParagraphStyleAttributeName:paragraphStyle};
        NSInteger right;
        NSInteger best = 0;
        do
        {
            right = next;
            NSRange range = NSMakeRange(0, right + 1);
            NSString *substring = [text substringWithRange:range];
            CGSize textSize = [substring boundingRectWithSize:maxSize
                                                      options:NSStringDrawingUsesLineFragmentOrigin
                                                   attributes:attributes
                                                      context:nil].size;
            if (textSize.width <= labelSize.width && textSize.height <= labelSize.height)
            {
                visibleRange = range;
                best = right;
                next = right + (max - right) / 2;
            } else if (right > 0)
            {
                next = right - (right - best) / 2;
            }
        } while (next != right);
    }
    return visibleRange;
}
hpique
  • 119,096
  • 131
  • 338
  • 476