Eyal Eyal - 8 months ago 77
iOS Question

Truncate UILabel in specific location

I use a table view to show a list of books, where each cell has a

that shows the book's name and another
the shows the book's author(s)

My question is about the author(s) label. A book can have multiple authors, and I want it to behave as follows:

  • If book has one author ('John Colman') label should be: "John Colman"

  • If book has more than one author ('John Colman', 'Bob Night', 'Michael') label should be: "John Colman +2 authors"

Now the problem is this, I want the label to be truncated before the '+'. So for example, if the first author name is long, lets say 'Benjamin Walter Jackson', I want the label to look like this:

"Benjamin Walter Ja... +2 authors"

The default behaviour of course truncates the label in the end, so it looks like this:

"Benjamin Walter Jackson +2 au..."

If I use the middle truncate, there's no promise that it will truncate the label in the right place (before the '+')

I'm looking for a way to do it and as efficient as possible, without impacting the scroll performance of the table view.


Edit: Generalized the solution to work with any "truncation location" string. Previous version only truncated at instance of string @" +". Edit allows you to define where you want the truncation to happen.

I took my answer from this question (which was an answer modified from the answer on this site) and tailored it to fit your needs. Create a new NSString interface where you can send your string to be custom-truncated.

NOTE: This solution is for iOS 7+ only. To use in iOS 6, use sizeWithFont: instead of sizeWithAttributes: in the NSString+TruncateToWidth.m file.


@interface NSString (TruncateToWidth)
- (NSString*)stringByTruncatingAtString:(NSString *)string toWidth:(CGFloat)width withFont:(UIFont *)font;


#import "NSString+TruncateToWidth.h"

#define ellipsis @"…"

@implementation NSString (TruncateToWidth)

- (NSString*)stringByTruncatingAtString:(NSString *)string toWidth:(CGFloat)width withFont:(UIFont *)font
    // If the string is already short enough, or 
    // if the 'truncation location' string doesn't exist
    // go ahead and pass the string back unmodified.
    if ([self sizeWithAttributes:@{NSFontAttributeName:font}].width < width ||
        [self rangeOfString:string].location == NSNotFound)
        return self;

    // Create copy that will be the returned result
    NSMutableString *truncatedString = [self mutableCopy];

    // Accommodate for ellipsis we'll tack on the beginning
    width -= [ellipsis sizeWithAttributes:@{NSFontAttributeName:font}].width;

    // Get range of the passed string. Note that this only works to the first instance found,
    // so if there are multiple, you need to modify your solution
    NSRange range = [truncatedString rangeOfString:string];
    range.length = 1;

    while([truncatedString sizeWithAttributes:@{NSFontAttributeName:font}].width > width)
        range.location -= 1;
        [truncatedString deleteCharactersInRange:range];

    // Append ellipsis
    range.length = 0;
    [truncatedString replaceCharactersInRange:range withString:ellipsis];

    return truncatedString;


Using it:

// Make sure to import the header file where you want to use it
myLabel.text = [@"Benjamin Walker Jackson + 2 authors" stringByTruncatingAtString:@" +" toWidth:myLabel.frame.size.width withFont:myLabel.font];
// Sample Result: Benjamin Walte... + 2 authors