Как установить выравнивание по левому краю для приложения UILabel для iOS? - PullRequest
87 голосов
/ 25 августа 2011

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

Например:

enter image description here

Что выглядит странно: (

Можно ли как-нибудь настроить текст метки в соответствии с выравниванием по левому верху?

Ответы [ 18 ]

64 голосов
/ 26 августа 2011

Это довольно легко сделать. Создайте подкласс UILabel со свойством verticalAlignment и переопределите textRectForBounds:limitedToNumberOfLines, чтобы получить правильные границы для верхнего, среднего или нижнего вертикального выравнивания. Вот код:

SOLabel.h

#import <UIKit/UIKit.h>

typedef enum
{
    VerticalAlignmentTop = 0, // default
    VerticalAlignmentMiddle,
    VerticalAlignmentBottom,
} VerticalAlignment;

@interface SOLabel : UILabel

   @property (nonatomic, readwrite) VerticalAlignment verticalAlignment;

@end

SOLabel.m

@implementation SOLabel

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) return nil;

    // set inital value via IVAR so the setter isn't called
    _verticalAlignment = VerticalAlignmentTop;

    return self;
}

-(VerticalAlignment) verticalAlignment
{
    return _verticalAlignment;
}

-(void) setVerticalAlignment:(VerticalAlignment)value
{
    _verticalAlignment = value;
    [self setNeedsDisplay];
}

// align text block according to vertical alignment settings
-(CGRect)textRectForBounds:(CGRect)bounds 
    limitedToNumberOfLines:(NSInteger)numberOfLines
{
   CGRect rect = [super textRectForBounds:bounds 
                   limitedToNumberOfLines:numberOfLines];
    CGRect result;
    switch (_verticalAlignment)
    {
       case VerticalAlignmentTop:
          result = CGRectMake(bounds.origin.x, bounds.origin.y, 
                              rect.size.width, rect.size.height);
           break;

       case VerticalAlignmentMiddle:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
                    rect.size.width, rect.size.height);
          break;

       case VerticalAlignmentBottom:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height),
                    rect.size.width, rect.size.height);
          break;

       default:
          result = bounds;
          break;
    }
    return result;
}

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

@end
59 голосов
/ 25 августа 2011

Вместо повторного объяснения я сошлюсь на этот довольно обширный и высоко оцененный вопрос / ответ:

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

Короткий ответ - нет, Apple не сделала это простым, но это возможно, изменив размер кадра.

37 голосов
/ 23 ноября 2014

SOLabel работает для меня.

Swift 1:

class UIVerticalAlignLabel: UILabel {

enum VerticalAlignment : Int {
    case VerticalAlignmentTop = 0
    case VerticalAlignmentMiddle = 1
    case VerticalAlignmentBottom = 2
}

var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
    didSet {
        setNeedsDisplay()
    }
}

required init(coder aDecoder: NSCoder){
    super.init(coder: aDecoder)
}

override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
    let rect = super.textRectForBounds(bounds, limitedToNumberOfLines: limitedToNumberOfLines)

    switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height)
        default:
            return bounds
    }
}

override func drawTextInRect(rect: CGRect) {
    let r = self.textRectForBounds(rect, limitedToNumberOfLines: self.numberOfLines)
    super.drawTextInRect(r)
    }
}

Swift 3:

Эта версия была обновлена ​​с оригинальной версии, чтобы обеспечить поддержку языков RTL:

public class VerticalAlignLabel: UILabel {
    enum VerticalAlignment {
        case top
        case middle
        case bottom
    }

    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }

    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
            switch verticalAlignment {
            case .top:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        } else {
            switch verticalAlignment {
            case .top:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        }
    }

    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}
36 голосов
/ 01 апреля 2016

Я нашел решение с помощью AutoLayout в StoryBoard.

1) Установите количество строк в 0 и выравнивание текста влево.

enter image description here

2) Установить ограничение по высоте.

enter image description here

3) Ограничение высоты должно быть в отношении - меньше или равно

enter image description here

4)

   override func viewWillLayoutSubviews() {
        sampleLabel.sizeToFit()
    }

Я получил следующий результат:

enter image description here

12 голосов
/ 10 марта 2012

в вашем коде

label.text = @"some text";
[label sizeToFit];

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

7 голосов
/ 23 марта 2015

Я нашел другое решение для той же проблемы. Я использовал UITextView вместо UILabel и переключил функцию editable() на false.

6 голосов
/ 20 ноября 2013

У меня тоже была эта проблема, но я обнаружил, что порядок, в котором вы устанавливаете свойства и методы UILabel, имеет значение!

Если вы вызываете [label sizeToFit] до label.font = [UIFont fontWithName:@"Helvetica" size:14];, то текст не выравниваетсянаверх, но если вы поменяете их местами, то это произойдет!

Я также заметил, что установка текста вначале тоже имеет значение.

Надеюсь, это поможет.

4 голосов
/ 28 июля 2018

В моем случае это была проблема bottom space. Я установил его на = 16.

Когда я установил значение bottom to >= 16, эта проблема была решена.

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

Вот представление ограничения моей метки в инспекторе размера:

constraint

4 голосов
/ 28 января 2015

Поскольку вы используете конструктор интерфейса, установите ограничения для вашей метки (не забудьте также установить высоту и ширину). Затем в инспекторе размера проверьте высоту метки. Там вы захотите прочитать> = вместо =. Затем в реализации для этого контроллера представления установите число строк равным 0 (это также можно сделать в IB) и установите метку [label sizeToFit]; и по мере того, как ваш текст набирает длину, высота метки будет увеличиваться, и текст останется в верхнем левом углу.

3 голосов
/ 28 марта 2017

Самый простой и легкий способ - вставить Label в StackView и установить Ось StackView в горизонтальное положение, выравнивание по верху в Инспекторе атрибутов из раскадровки , как показано здесь .

...