Выровнять текст по вертикали внутри UILabel - PullRequest
2098 голосов
/ 28 июня 2009

У меня есть UILabel с пробелом для двух строк текста. Иногда, когда текст слишком короткий, этот текст отображается в вертикальном центре метки.

Как мне выровнять текст по вертикали, чтобы всегда быть в верхней части UILabel?

image representing a UILabel with vertically-centered text

Ответы [ 48 ]

14 голосов
/ 14 сентября 2010

Я хотел иметь метку, которая могла бы иметь несколько строк, минимальный размер шрифта и центрироваться как по горизонтали, так и по вертикали в родительском представлении. Я добавил мой ярлык программно на мой взгляд:

- (void) customInit {
    // Setup label
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.label.numberOfLines = 0;
    self.label.lineBreakMode = UILineBreakModeWordWrap;
    self.label.textAlignment = UITextAlignmentCenter;

    // Add the label as a subview
    self.autoresizesSubviews = YES;
    [self addSubview:self.label];
}

А потом, когда я захотел изменить текст моего ярлыка ...

- (void) updateDisplay:(NSString *)text {
    if (![text isEqualToString:self.label.text]) {
        // Calculate the font size to use (save to label's font)
        CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
        self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
        CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
            self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
            textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        }
        // In cases where the frame is still too large (when we're exceeding minimum font size),
        // use the views size
        if (textSize.height > self.frame.size.height) {
            textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
        }

        // Draw 
        self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
        self.label.text = text;
    }
    [self setNeedsDisplay];
}

Надеюсь, это кому-нибудь поможет!

14 голосов
/ 29 апреля 2014

Я обнаружил, что ответы на этот вопрос теперь немного устарели, поэтому добавим его для поклонников автоматического макета.

Авторазметка делает эту проблему довольно тривиальной. Предполагая, что мы добавляем метку к UIView *view, следующий код выполнит это:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];

[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];

Высота метки будет рассчитываться автоматически (используя ее intrinsicContentSize), и метка будет располагаться по горизонтали, в верхней части view.

11 голосов
/ 01 марта 2011

для любого, кто читает это, потому что текст внутри вашего ярлыка не центрирован по вертикали, имейте в виду, что некоторые типы шрифтов не разработаны одинаково. например, если вы создадите метку с размером zapfino 16, вы увидите, что текст не идеально отцентрирован по вертикали.

однако, работа с helvetica будет центрировать ваш текст по вертикали.

11 голосов
/ 19 мая 2018

В моем приложении я установил для свойства линии UILabel значение 0, а также для создания нижнего ограничения UILabel и убедитесь, что для него задано значение> = 0, как показано на рисунке ниже. enter image description here

10 голосов
/ 03 июля 2012

Подкласс UILabel и ограничение прямоугольника рисования, например:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];
    rect.size.height = MIN(rect.size.height, sizeThatFits.height);

    [super drawTextInRect:rect];
}

Я попробовал решение, включающее заполнение новой строки, и в некоторых случаях столкнулся с некорректным поведением. По моему опыту, проще ограничить прямоугольник рисования, как указано выше, чем связываться с numberOfLines.

P.S. Вы можете легко представить поддержку UIViewContentMode следующим образом:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];

    if (self.contentMode == UIViewContentModeTop) {
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }
    else if (self.contentMode == UIViewContentModeBottom) {
        rect.origin.y = MAX(0, rect.size.height - sizeThatFits.height);
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }

    [super drawTextInRect:rect];
}
10 голосов
/ 05 сентября 2013

Если вы используете autolayout, установите для вертикального contentHuggingPriority значение 1000, либо в коде, либо в IB. В IB вам, возможно, придется удалить ограничение высоты, установив его приоритет на 1, а затем удалив его.

9 голосов
/ 28 декабря 2016

Использование textRect(forBounds:limitedToNumberOfLines:).

class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        super.drawText(in: textRect)
    }
}
8 голосов
/ 12 марта 2012

Пока вы не выполняете никаких сложных задач, вы можете использовать UITextView вместо UILabels.

Отключить прокрутку.

Если вы хотите, чтобы текст отображался полностью, используйте только пользовательские sizeToFit и sizeThatFits: методы

8 голосов
/ 23 февраля 2016

В быстром

let myLabel : UILabel!

Чтобы ваш текст метки помещался на экране, и он был сверху

myLabel.sizeToFit()

Чтобы ваш шрифт метки соответствовал ширине экрана или определенному размеру ширины.

myLabel.adjustsFontSizeToFitWidth = YES

и некоторые текстовые выравнивания для метки:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified

7 голосов
/ 28 сентября 2011

Это старое решение, используйте autolayout на iOS> = 6

Мое решение:
1 / Разделить линии самостоятельно (игнорируя настройки переноса меток)
2 / Нарисуйте линии самостоятельно (игнорируя выравнивание меток)


@interface UITopAlignedLabel : UILabel

@end

@implementation UITopAlignedLabel

#pragma mark Instance methods

- (NSArray*)splitTextToLines:(NSUInteger)maxLines {
    float width = self.frame.size.width;

    NSArray* words = [self.text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSMutableArray* lines = [NSMutableArray array];

    NSMutableString* buffer = [NSMutableString string];    
    NSMutableString* currentLine = [NSMutableString string];

    for (NSString* word in words) {
        if ([buffer length] > 0) {
            [buffer appendString:@" "];
        }

        [buffer appendString:word];

        if (maxLines > 0 && [lines count] == maxLines - 1) {
            [currentLine setString:buffer];
            continue;
        }

        float bufferWidth = [buffer sizeWithFont:self.font].width;

        if (bufferWidth < width) {
            [currentLine setString:buffer];
        }
        else {
            [lines addObject:[NSString stringWithString:currentLine]];

            [buffer setString:word];
            [currentLine setString:buffer];
        }
    }

    if ([currentLine length] > 0) {
        [lines addObject:[NSString stringWithString:currentLine]];
    }

    return lines;
}

- (void)drawRect:(CGRect)rect {
    if ([self.text length] == 0) {
        return;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, self.textColor.CGColor);
    CGContextSetShadowWithColor(context, self.shadowOffset, 0.0f, self.shadowColor.CGColor);

    NSArray* lines = [self splitTextToLines:self.numberOfLines];
    NSUInteger numLines = [lines count];

    CGSize size = self.frame.size;
    CGPoint origin = CGPointMake(0.0f, 0.0f);

    for (NSUInteger i = 0; i < numLines; i++) {
        NSString* line = [lines objectAtIndex:i];

        if (i == numLines - 1) {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeTailTruncation];            
        }
        else {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeClip];
        }

        origin.y += self.font.lineHeight;

        if (origin.y >= size.height) {
            return;
        }
    }
}

@end
...