Многострочный UILabel без переноса слов?

Возможно ли иметь UILabel который состоит из нескольких \nлимит строк, чтобы иметь ширину> ширину метки, которая должна быть обрезана и не обернута?

Предположим, у меня есть текст вроде следующего:

  1. Это действительно длинная первая строка текста, которая слишком длинна, чтобы поместиться горизонтально
  2. Короткая линия
  3. Еще одна короткая линия

Я хочу, чтобы это появилось в моем UILabel вот так:

1. Это действительно длинная первая строка текста...
2. Короткая линия
3. Еще одна короткая очередь

Однако, что происходит, я получаю это:

1. Это действительно длинная первая строка текста  
это слишком долго, чтобы поместиться горизонтально
2. Короткая линия...

Третья строка обрезается. Я установил количество строк в 3, но он все еще переносит первую длинную строку. Кажется, не имеет значения, для чего я установил свойство разрыва строки на метке - он всегда переносит эту первую строку. Есть ли какой-нибудь способ полностью обернуть этикетку?

1 ответ

Решение

Я не думаю, что это возможно при любой настройке, которую вы можете применить к своему лейблу. Один из способов сделать это - разбить строку на отдельные строки, обрезать любую нужную ей строку так, чтобы она (с добавленным многоточием) поместилась на одной строке, а затем снова поместить строку вместе с разрывами строк. Примерно так должно работать на любое количество строк,

@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;
}

Если вы хотите обрезать по символу, а не по слову, вы можете передать NSStringEnumerationByComposedCharacterSequence вместо NSStringEnumerationByWords в параметр options enumerateSubstringsInRange:options:usingBlock:.

Конечно, вы могли бы сделать это простым способом; сложите 3 надписи друг над другом и дайте каждому строчку своего текста:)

Другие вопросы по тегам