Как установить выравнивание по левому краю для UILabel для приложения iOS?

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

Например:

enter image description here

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

Есть ли способ, которым я могу установить правильный текст метки для выравнивания Top-Left?

Ответ 2

Это довольно легко сделать. Создайте подкачку 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

Ответ 3

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

1) Не устанавливайте строки в 0 и выравнивание текста влево.

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

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

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

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

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

4)

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

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

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

Ответ 4

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)
    }
}

Ответ 5

В вашем коде

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

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

Ответ 6

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

Ответ 7

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

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

Я также заметил, что установка текста в первую очередь также имеет значение.

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

Ответ 8

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

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

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

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

constraint

Ответ 9

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

Ответ 10

Решение с SoLabel работает, спасибо.

Bellow Я добавил версию monotouch:

    public class UICustomLabel : UILabel
{
    private UITextVerticalAlignment _textVerticalAlignment;

    public UICustomLabel()
    {
        TextVerticalAlignment = UITextVerticalAlignment.Top;
    }

    public UITextVerticalAlignment TextVerticalAlignment
    {
        get
        {
            return _textVerticalAlignment;
        }
        set
        {
            _textVerticalAlignment = value;
            SetNeedsDisplay();
        }
    }

    public override void DrawText(RectangleF rect)
    {
        var bound = TextRectForBounds(rect, Lines);
        base.DrawText(bound);
    }

    public override RectangleF TextRectForBounds(RectangleF bounds, int numberOfLines)
    {
        var rect = base.TextRectForBounds(bounds, numberOfLines);
        RectangleF resultRect;
        switch (TextVerticalAlignment)
        {
            case UITextVerticalAlignment.Top:
                resultRect = new RectangleF(bounds.X, bounds.Y, rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Middle:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height)/2,
                                            rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Bottom:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height),
                                            rect.Size.Width, rect.Size.Height);
                break;

            default:
                resultRect = bounds;
                break;
        }

        return resultRect;
    }
}

public enum UITextVerticalAlignment
{
    Top = 0, // default
    Middle,
    Bottom
}

Ответ 11

Самый простой и простой способ - вставить Label в StackView и установить Axis StackView в Horizontal, Alignment to Top в Attribute Inspector из Storyboard как показано здесь.

Ответ 12

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

textview.isEditable = false

Путь проще, чем возиться с метками...

Ура!

Ответ 13

Основываясь на потрясающем ответе totiG, я создал класс IBDesignable, который чрезвычайно упрощает настройку вертикального выравнивания UILabel прямо из StoryBoard. Просто убедитесь, что вы установили для своего класса UILabel значение "VerticalAlignLabel" из инспектора идентификации StoryBoard. Если вертикальное выравнивание не вступает в силу, перейдите к Editor-> Обновить все виды, что должно помочь.

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

Обновление: я добавил поддержку центрированных меток ~ Sev


Введите 0 для верхнего выравнивания

Введите 1 для среднего выравнивания

Введите 2 для нижнего выравнивания

    @IBDesignable class VerticalAlignLabel: UILabel {
    
    @IBInspectable var alignmentCode: Int = 0 {
        didSet {
            applyAlignmentCode()
        }
    }
    
    func applyAlignmentCode() {
        switch alignmentCode {
        case 0:
            verticalAlignment = .top
        case 1:
            verticalAlignment = .topcenter
        case 2:
            verticalAlignment = .middle
        case 3:
            verticalAlignment = .bottom
        default:
            break
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.applyAlignmentCode()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        
        self.applyAlignmentCode()
    }
    
    enum VerticalAlignment {
        case top
        case topcenter
        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 #available(iOS 9.0, *) {
            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 .topcenter:
                    return CGRect(x: self.bounds.size.width - (rect.size.width / 2), 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 .topcenter:
                    return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), 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)
                }
            }
        } else {
            // Fallback on earlier versions
            return rect
        }
    }
    
    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

Ответ 14

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

Ответ 15

Для iOS 7, что я сделал и работал у меня

@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                              attributes:attributes
                                                 context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    CGRect newFrame = self.frame;
    newFrame.size.height = numberOfLines * self.font.lineHeight;
    self.frame = newFrame;
}

- (void)alignBottom
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                            attributes:attributes
                                               context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    int numberOfNewLined = (self.frame.size.height/self.font.lineHeight) - numberOfLines;

    NSMutableString *newLines = [NSMutableString string];
    for(int i=0; i< numberOfNewLined; i++){
        [newLines appendString:@"\n"];
    }
    [newLines appendString:self.text];
    self.text = [newLines mutableCopy];
}

Ответ 16

Swift 2.0:: использование расширения UILabel

Сделать постоянными значениями перечисления в пустом файле Swift.

//  AppRef.swift

import UIKit
import Foundation

enum UILabelTextPositions : String {

 case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
 case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
 case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"

}

Использование расширения UILabel:

Создайте пустой класс Swift и назовите его. Добавьте следующее.

//  AppExtensions.swift

import Foundation
import UIKit

    extension UILabel{ 
     func makeLabelTextPosition (sampleLabel :UILabel?, positionIdentifier : String) -> UILabel
     {
      let rect = sampleLabel!.textRectForBounds(bounds, limitedToNumberOfLines: 0)

      switch positionIdentifier
      {
      case "VerticalAlignmentTop":
       sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y, rect.size.width, rect.size.height)
       break;

      case "VerticalAlignmentMiddle":
       sampleLabel!.frame = CGRectMake(bounds.origin.x+5,bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
        rect.size.width, rect.size.height);
       break;

      case "VerticalAlignmentBottom":
       sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y + (bounds.size.height - rect.size.height),rect.size.width, rect.size.height);
       break;

      default:
       sampleLabel!.frame = bounds;
       break;
      }
      return sampleLabel!

     }
    }

Использование:

myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)

Ответ 17

Свифт 3 версии ответа @totiG

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

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

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

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

        switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentMiddle:
            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 .VerticalAlignmentBottom:
            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 func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

Ответ 18

У меня есть эта проблема, но мой ярлык был в UITableViewCell, и в фонде самым простым способом решения этой проблемы было создание пустого UIView и установка метки внутри него с ограничениями только сверху и только с левой стороны, вне проклятия установить количество строк в 0

Ответ 19

Как установить выравнивание по левому верху для приложения UILabel для iOS? Лейбл Set Content Mode на "Top Left" работает для меня, большое спасибо:
How to set top-left alignment for UILabel for iOS application? Label Set Content Mode to "Top Left" work for me, thank you very much