I don't think this is possible with any setting you can apply to your label. One way to do it, is to break the string into its individual lines, truncate any line that needs it so that it (with an added ellipsis) fits on one line, then put the string back together with line breaks. Something like this should work for any number of lines,
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (nonatomic) CGFloat ellipsisWidth;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *text = @"This is a really long first line of text that is too long to fit horizontally\nShort line\nAnother short line";
NSString *ellipsis = @"...";
self.ellipsisWidth = [ellipsis sizeWithAttributes:@{NSFontAttributeName:self.label.font}].width;
__block NSMutableString *truncatedString = [@"" mutableCopy];
[text enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
[truncatedString appendFormat:@"%@\n", [self oneLineOfString:line withFont:self.label.font]];
}];
NSString *finalString = [truncatedString stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
self.label.numberOfLines = 0;
self.label.text = finalString;
}
-(NSString *)oneLineOfString:(NSString *) aLine withFont:(UIFont *) font {
__block NSString *singleLine = nil;
__block NSString *lastFragment;
[aLine enumerateSubstringsInRange:NSMakeRange(0, aLine.length) options:NSStringEnumerationByWords usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
NSString *textFragment = [aLine substringToIndex:(substringRange.location + substringRange.length)];
CGRect textRect = [textFragment boundingRectWithSize:CGSizeMake(CGFLOAT_MAX ,CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil];
if (textRect.size.width >= self.label.bounds.size.width - self.ellipsisWidth) {
singleLine = [lastFragment stringByAppendingString:@"..."];
*stop = YES;
}
lastFragment = textFragment;
}];
if (!singleLine) singleLine = aLine; // it doesn't need to be truncated, so return the passed in line
return singleLine;
}
If you want to truncate by character instead of by word, you can pass NSStringEnumerationByComposedCharacterSequences instead of NSStringEnumerationByWords to the options parameter of
enumerateSubstringsInRange:options:usingBlock:.
Of course, you could do it the easy way; stack 3 labels on top of each other, and give each one a line of your text :)