Подтвердить что ты не робот

Вертикально выравнивать текст вверху в UILabel

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

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

image representing a UILabel with vertically-centered text

4b9b3361

Ответ 1

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

Вот быстрый и простой способ сделать это:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


Если у вас есть метка с более длинным текстом, который будет занимать более одной строки, установите для numberOfLines значение 0 (ноль здесь означает неограниченное количество строк).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Более длинная версия

Я сделаю свою метку в коде, чтобы вы могли видеть, что происходит. Вы можете настроить большую часть этого в Интерфейсном Разработчике также. Моя установка представляет собой приложение на основе вида с фоновым изображением, которое я сделал в Photoshop для отображения полей (20 баллов). Этикетка имеет привлекательный оранжевый цвет, поэтому вы можете видеть, что происходит с размерами.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 20 point top and left margin. Sized to leave 20 pt at right.
    CGRect labelFrame = CGRectMake(20, 20, 280, 150);
    UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
    [myLabel setBackgroundColor:[UIColor orangeColor]];

    NSString *labelText = @"I am the very model of a modern Major-General, I've information vegetable, animal, and mineral";
    [myLabel setText:labelText];

    // Tell the label to use an unlimited number of lines
    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    [self.view addSubview:myLabel];
}

Некоторые ограничения использования sizeToFit вступают в игру с center- или текстом, выровненным по правому краю. Вот что происходит:

    // myLabel.textAlignment = NSTextAlignmentRight;
    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

enter image description here

Ярлык по-прежнему имеет фиксированный верхний левый angular. Вы можете сохранить исходную ширину метки в переменной и установить ее после sizeToFit или задать фиксированную ширину, чтобы противостоять этим проблемам:

    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    CGRect myFrame = myLabel.frame;
    // Resize the frame width to 280 (320 - margins)
    // width could also be myOriginalLabelFrame.size.width
    myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
    myLabel.frame = myFrame;

label alignment


Обратите внимание, что sizeToFit будет учитывать минимальную ширину вашей начальной метки. Если вы начнете с метки шириной 100 и назовете sizeToFit, она вернет вам (возможно, очень высокий) ярлык шириной 100 (или чуть меньше). Возможно, вы захотите установить для метки минимальную ширину, которую хотите, до изменения размера.

Correct label alignment by resizing the frame width

Некоторые другие вещи, на которые стоит обратить внимание:

Соблюдение lineBreakMode зависит от того, как он установлен. NSLineBreakByTruncatingTail (по умолчанию) игнорируется после sizeToFit, как и два других режима усечения (головной и средний). NSLineBreakByClipping также игнорируется. NSLineBreakByCharWrapping работает как обычно. Ширина рамки все еще сужена, чтобы соответствовать самой правой букве.


Марк Эмери дал исправление для NIB и раскадровок, используя Auto Layout в комментариях:

Если ваша метка включена в перо или раскадровку в качестве подпредставления view ViewController, который использует autolayout, то помещение вашего вызова sizeToFit в viewDidLoad не будет работать, потому что размеры autoolayout и расположение подпредставлений после viewDidLoad вызывается и немедленно отменяет эффекты вашего вызова sizeToFit. Однако вызов sizeToFit из viewDidLayoutSubviews будет работать.


Мой оригинальный ответ (для потомков/справок):

При этом используется метод NSString sizeWithFont:constrainedToSize:lineBreakMode: для вычисления высоты кадра, необходимой для размещения строки, а затем задается источник и ширина.

Измените размер рамки для метки, используя текст, который вы хотите вставить. Таким образом, вы можете разместить любое количество строк.

CGSize maximumSize = CGSizeMake(300, 9999);
NSString *dateString = @"The date today is January 1st, 1999";
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [dateString sizeWithFont:dateFont 
        constrainedToSize:maximumSize 
        lineBreakMode:self.dateLabel.lineBreakMode];

CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);

self.dateLabel.frame = dateFrame;

Ответ 2

  1. Установите новый текст:

    myLabel.text = @"Some Text"
    
  2. Установите maximum number строк в 0 (автоматически):

    myLabel.numberOfLines = 0
    
  3. Установите максимальный размер рамки этикетки:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. Вызовите sizeToFit, чтобы уменьшить размер кадра, чтобы содержимое точно подходило:

    [myLabel sizeToFit]
    

Рамка для надписей теперь достаточно высокая и достаточно широкая, чтобы вместить ваш текст. Верхний левый должен быть неизменным. Я проверял это только с выравниванием по верхнему левому краю текста. Для других выравниваний вам, возможно, придется изменить кадр позже.

Кроме того, на моем ярлыке включена перенос слов.

Ответ 3

Ссылаясь на решение для расширения:

for(int i=1; i< newLinesToPad; i++) 
    self.text = [self.text stringByAppendingString:@"\n"];

следует заменить на

for(int i=0; i<newLinesToPad; i++)
    self.text = [self.text stringByAppendingString:@"\n "];

В каждой добавленной новой строке требуется дополнительное пространство, потому что возврат к возврату каретки iPhone UILabels ', кажется, игнорируется: (

Аналогично, alignBottom также должен быть обновлен с помощью @" \[email protected]%" вместо "\[email protected]%" (для инициализации цикла необходимо заменить на "for (int я = 0..." ).

Для меня работает следующее расширение:

// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end

// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [self.text stringByAppendingString:@"\n "];
}

- (void)alignBottom {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end

Затем вызовите [yourLabel alignTop]; или [yourLabel alignBottom]; после каждого назначения текста yourLabel.

Ответ 4

На всякий случай, если бы это помогало кому-либо, у меня была такая же проблема, но я смог решить проблему, просто переключившись с UILabel на UITextView. Я понимаю, что это не для всех, потому что функциональность немного отличается.

Если вы переключитесь на использование UITextView, вы можете отключить все свойства просмотра прокрутки, а также включенное взаимодействие с пользователем... Это заставит его действовать как ярлык.

введите описание изображения здесь

Ответ 5

Нет суеты, нет суеты

@interface MFTopAlignedLabel : UILabel

@end


@implementation MFTopAlignedLabel

- (void)drawTextInRect:(CGRect) rect
{
    NSAttributedString *attributedText = [[NSAttributedString alloc]     initWithString:self.text attributes:@{NSFontAttributeName:self.font}];
    rect.size.height = [attributedText boundingRectWithSize:rect.size
                                            options:NSStringDrawingUsesLineFragmentOrigin
                                            context:nil].size.height;
    if (self.numberOfLines != 0) {
        rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight);
    }
    [super drawTextInRect:rect];
}

@end

Нет суеты, нет Objective-c, нет суеты, кроме Swift 3:

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSFontAttributeName: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

Swift 4.2

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

Ответ 6

Как и в предыдущем ответе, но это было не совсем правильно или легко похлопать по коду, поэтому я немного почистил его. Добавьте это расширение либо к своему собственному файлу .h и .m, либо просто вставьте прямо над реализацией, которую вы собираетесь использовать:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end


@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i<= newLinesToPad; i++)
    {
        self.text = [self.text stringByAppendingString:@" \n"];
    }
}

- (void)alignBottom
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i< newLinesToPad; i++)
    {
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
    }
}
@end

И затем, чтобы использовать, поместите текст в метку, а затем вызовите соответствующий метод для его выравнивания:

[myLabel alignTop];

или

[myLabel alignBottom];

Ответ 7

Еще более быстрый (и более грязный) способ выполнить это, установив режим разрыва строки UILabel на "Clip" и добавив фиксированное количество строк новой строки.

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];

Это решение не будет работать для всех - в частности, если вы все еще хотите показать "..." в конце строки, если она превышает количество строк, которые вы показываете, вам нужно будет используйте один из более длинных битов кода, но для многих случаев это даст вам то, что вам нужно.

Ответ 8

Вместо UILabel вы можете использовать UITextField, у которого есть опция вертикального выравнивания:

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction

Ответ 9

Решение раскадровки: самым простым и простым способом является встраивание Label в StackView и установка Axis StackView в Horizontal, Alignment до Top в Attribute Inspector из раскадровки.

enter image description here

Ответ 10

Я долгое время боролся с этим, и я хотел поделиться своим решением.

Это даст вам UILabel, который будет автоматически печатать текст до 0,5 шкалы и вертикально центрировать текст. Эти параметры также доступны в Storyboard/IB.

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];

Ответ 11

Создайте новый класс

LabelTopAlign

.h файл

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

.m file

#import "KwLabelTopAlign.h"


@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect {
    int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
    if(rect.size.height >= lineHeight) {
        int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
        int yMax = textHeight;
        if (self.numberOfLines > 0) {
            yMax = MIN(lineHeight*self.numberOfLines, yMax);    
        }

        [super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
    }
}

@end

Изменить

Здесь выполняется более простая реализация, которая делает то же самое:

#import "KwLabelTopAlign.h"

@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect
{
    CGFloat height = [self.text sizeWithFont:self.font
                            constrainedToSize:rect.size
                                lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    [super drawTextInRect:rect];
}

@end

Ответ 12

enter image description here

В интерфейсе Builder

  • Установите UILabel размер максимально возможного текста
  • Установите Lines в '0' в Инспекторе атрибутов

В вашем коде

  • Установите текст метки
  • Вызов sizeToFit на вашей этикетке

Фрагмент кода:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];

Ответ 13

Для Adaptive UI (iOS8 или после) вертикальное выравнивание UILabel должно быть установлено из StoryBoard путем изменения свойств   noOfLines= 0` и

Ограничения

  • Корректировка ограничений UILabel LefMargin, RightMargin и Top Margin.

  • Измените Content Compression Resistance Priority For Vertical= 1000` Чтобы вертикальный > горизонтальный.

Ограничения UILabel

Отредактировано:

noOfLines=0

и для достижения желаемых результатов достаточно следующих ограничений.

введите описание изображения здесь

Ответ 14

Создайте подкласс UILabel. Работает как шарм:

// TopLeftLabel.h

#import <Foundation/Foundation.h>

@interface TopLeftLabel : UILabel 
{
}

@end

// TopLeftLabel.m

#import "TopLeftLabel.h"

@implementation TopLeftLabel

- (id)initWithFrame:(CGRect)frame 
{
    return [super initWithFrame:frame];
}

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines 
{
    CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];    
    textRect.origin.y = bounds.origin.y;
    return textRect;
}

-(void)drawTextInRect:(CGRect)requestedRect 
{
    CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:actualRect];
}

@end

Как обсуждалось здесь.

Ответ 15

Я написал функцию утилиты для достижения этой цели. Вы можете посмотреть:

// adjust the height of a multi-line label to make it align vertical with top
+ (void) alignLabelWithTop:(UILabel *)label {
  CGSize maxSize = CGSizeMake(label.frame.size.width, 999);
  label.adjustsFontSizeToFitWidth = NO;

  // get actual height
  CGSize actualSize = [label.text sizeWithFont:label.font constrainedToSize:maxSize lineBreakMode:label.lineBreakMode];
  CGRect rect = label.frame;
  rect.size.height = actualSize.height;
  label.frame = rect;
}

.Как использовать? (Если lblHello создается конструктором интерфейса, поэтому я пропускаю некоторые атрибуты атрибутов UILabel)

lblHello.text = @"Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!";
lblHello.numberOfLines = 5;
[Utils alignLabelWithTop:lblHello];

Я также написал это в своем блоге как статью: http://fstoke.me/blog/?p=2819

Ответ 16

Мне потребовалось некоторое время, чтобы прочитать код, а также код на введенной странице и обнаружили, что все они пытаются изменить размер фрейма метки, так что центральное вертикальное выравнивание по умолчанию не появится.

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

Здесь я использовал альтернативный способ его решения, просто добавив новые строки в конец метки (обратите внимание, что я действительно унаследовал UILabel, но это необязательно):

CGSize fontSize = [self.text sizeWithFont:self.font];

finalHeight = fontSize.height * self.numberOfLines;
finalWidth = size.width;    //expected width of label

CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];

int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

for(int i = 0; i < newLinesToPad; i++)
{
    self.text = [self.text stringByAppendingString:@"\n "];
}

Ответ 17

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

@interface TopAlignedLabelContainer : UIView
{
}

@end

@implementation TopAlignedLabelContainer

- (void)layoutSubviews
{
    CGRect bounds = self.bounds;

    for (UILabel *label in [self subviews])
    {
        if ([label isKindOfClass:[UILabel class]])
        {
            CGSize fontSize = [label.text sizeWithFont:label.font];

            CGSize textSize = [label.text sizeWithFont:label.font
                                     constrainedToSize:bounds.size
                                         lineBreakMode:label.lineBreakMode];

            label.numberOfLines = textSize.height / fontSize.height;

            label.frame = CGRectMake(0, 0, textSize.width,
                 fontSize.height * label.numberOfLines);
        }
    }
}

@end

Ответ 18

Вы можете использовать TTTAttributedLabel, он поддерживает вертикальное выравнивание.

@property (nonatomic) TTTAttributedLabel* label;
<...>

//view or viewController init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;

Ответ 19

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

myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];

Убедитесь, что количество строк в строке приведет к тому, что любой текст заполнит доступное вертикальное пространство и установите UILabel для обрезания любого переполняющего текста.

Потому что иногда достаточно хорошо.

Ответ 20

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

Автоматическая компоновка делает эту проблему довольно тривиальной. Предполагая, что мы добавляем метку к 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.

Ответ 21

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

Ответ 22

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

- (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 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];
}

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

Ответ 23

FXLabel (на github) делает это из коробки, устанавливая label.contentMode на UIViewContentModeTop. Этот компонент не сделан мной, но это компонент, который я часто использую и имеет множество функций, и, похоже, работает хорошо.

Ответ 24

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

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

Ответ 25

Подкласс 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];
}

Ответ 26

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

Ответ 27

Используйте textRect(forBounds:limitedToNumberOfLines:).

class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        super.drawText(in: textRect)
    }
}

Ответ 28

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

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

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

Ответ 29

В быстром,

let myLabel : UILabel!

Чтобы текст вашего ярлыка соответствовал экрану, а он сверху

myLabel.sizeToFit()

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

myLabel.adjustsFontSizeToFitWidth = YES

и некоторая textAlignment для метки:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified

Ответ 30

Это старое решение, используйте автоматическое расположение на 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