iOS Developer Tips - Visitor Stats:
|
|
|
Truncate a String and Append an Ellipsis, Respecting the Font Size
A number of the UI related controls will automatically truncate and append ellipsis with no effort required on your part. For example, with UILabel you can specify the linebreak mode to indicate how you would like the system to manage wrapping and truncating the label text.
However, they are times when having a method to truncate a string without using a UI control would be handy. In this post I’ll create a category which will add a method to the NSString class to do just that. You can read more about working with categories in this post: Introduction to Categories.
NSString Category
Start by creating a new interface file with the name: NSString+TruncateToWidth.h – appending the method name to the class is a common naming convention when working with categories.
The code below defines a method that will be available to all NSString objects. The method will truncate a string to a specific width, using the font size to properly determine the string size before truncating:
@interface NSString (TruncateToWidth) - (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(UIFont *)font; @end
Code to Truncate NSString
The implementation of the stringByTruncatingToWidth method follows, add this code to the NSString+TruncateToWidth.m file.
#import "NSString+TruncateToWidth.h" #define ellipsis @"…" @implementation NSString (TruncateToWidth) - (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(UIFont *)font { // Create copy that will be the returned result NSMutableString *truncatedString = [[self mutableCopy] autorelease]; // Make sure string is longer than requested width if ([self sizeWithFont:font].width > width) { // Accommodate for ellipsis we'll tack on the end width -= [ellipsis sizeWithFont:font].width; // Get range for last character in string NSRange range = {truncatedString.length - 1, 1}; // Loop, deleting characters until string fits within width while ([truncatedString sizeWithFont:font].width > width) { // Delete character at end [truncatedString deleteCharactersInRange:range]; // Move back another character range.location--; } // Append ellipsis [truncatedString replaceCharactersInRange:range withString:ellipsis]; } return truncatedString; } @end
Notice that the desired final width of the string is passed in, as well as the font that will be used when calculating the size (width) of the string. The process is quite simple: change the incoming width to accommodate an ellipsis on the end of the string – loop through the string removing characters from the end until the desired width is reached – append an ellipsis onto the string.
Calling the Truncate NSString Method
You can now call the method stringByTruncatingToWidth:withFont: on any NSString object:
NSString *str = @"Lorem ipsum dolor sit amet, consectetuer adipiscing"; // Adjust the width parameter to change the final string width str = [str stringByTruncatingToWidth:170 withFont:[UIFont systemFontOfSize:15]]; NSLog(@"%@", str);
The output from above would look as follows:
Lorem ipsum dolor sit…







Does NSString mutableCopy really return a string that needs to be released? By standard naming conventions, it should not.
You might want to generalize the string to be appended.
- (NSString*)stringByTruncatingStringToWidth:(CGFloat)width withFont:(UIFont *)font endingWith:(NSString*)endString { /* your implementation but using endString */ }
and implement your function as
- (NSString*)stringByTruncatingStringToWidth:(CGFloat)width withFont:(UIFont *)font
{
[self stringByTruncatingStringToWidth: width withFont: font endingWith: ellipsis];
}
But that’s just a small tweak.
[Reply]
Michelle, the docs state “If you are using managed memory (not garbage collection), this method retains the new object before returning it.” so the autorelease should do the trick…
[Reply]
Thank you for this post!
I have a problem with this implementation: Strings are cut, even if they are narrower
than the defined maximum width:
Example:
cell.textLabel.text = [news stringByTruncatingToWidth:240 withFont:[UIFont boldSystemFontOfSize:15]];
So every String is at least missing the last character and gets the ellipsis appended…
“Here is a superlong Title to…” -> correct
“Short Titl…” -> wrong
Cheers
Krille
[Reply]
John Muchow Reply:
July 27th, 2010 at 6:01 am
Krille, thanks for pointing that out. I’ve updated the code to check for the string length up front.
[Reply]
Great – thank you very much, everytime I learn something new from your articles!
[Reply]
Hello. Thank you for that. Is there any way to truncate multiline text? I mean adding to your category method like – (NSString*)stringByTruncatingToSize:(CGSize)size withFont:(UIFont *)font; Is it possible?
Thanks in advance.
[Reply]
how would you do the same thing for multiple lines where the ellipsis is only added to the last line?
[Reply]