it-swarm.com.ru

Выровнять текст по вертикали внутри UILabel (Примечание. Использование AutoLayout)

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

first screenshot

Ожидаемый дисплей, как показано ниже.

second screenshot

61
MELWIN

Правка

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

Для тех из вас, кто более комфортно использует Open Source, обязательно посмотрите на TTTAttributedLabel , где вы можете установить выравнивание текста метки на TTTAttributedLabelVerticalAlignmentTop


Хитрость заключается в том, чтобы создать подкласс UILabel и переопределить drawTextInRect. Затем убедитесь, что текст нарисован в начале границ метки.

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

Стриж

@IBDesignable class TopAlignedLabel: UILabel {
    override func drawTextInRect(rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            var labelStringSize = stringTextAsNSString.boundingRectWithSize(CGSizeMake(CGRectGetWidth(self.frame), CGFloat.max),
                options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                attributes: [NSFontAttributeName: font],
                context: nil).size
            super.drawTextInRect(CGRectMake(0, 0, CGRectGetWidth(self.frame), ceil(labelStringSize.height)))
        } else {
            super.drawTextInRect(rect)
        }
    }
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.blackColor().CGColor
    }
}

Свифт 3

  @IBDesignable class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width,height: CGFloat.greatestFiniteMagnitude),
                                                                            options: NSStringDrawingOptions.usesLineFragmentOrigin,
                                                                            attributes: [NSFontAttributeName: font],
                                                                            context: nil).size
            super.drawText(in: CGRect(x:0,y: 0,width: self.frame.width, height:ceil(labelStringSize.height)))
        } else {
            super.drawText(in: rect)
        }
    }
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.black.cgColor
    }
}

Objective-C

IB_DESIGNABLE
@interface TopAlignedLabel : UILabel

@end

@implementation TopAlignedLabel

- (void)drawTextInRect:(CGRect)rect {
    if (self.text) {
        CGSize labelStringSize = [self.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.frame), CGFLOAT_MAX)
                                                         options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                                      attributes:@{NSFontAttributeName:self.font}
                                                         context:nil].size;
        [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),ceilf(labelStringSize.height))];
    } else {
        [super drawTextInRect:rect];
    }
}

- (void)prepareForInterfaceBuilder {
        [super prepareForInterfaceBuilder];
        self.layer.borderWidth = 1;
        self.layer.borderColor = [UIColor blackColor].CGColor;
}

@end

Поскольку я использовал IBDesignable, вы можете добавить этот ярлык на раскадровку и посмотреть, как он выглядит, для меня это выглядит так

enter image description here

128
Daniel Galasko

Если вы не ограничены наличием UILabel фиксированного размера, вместо выравнивания текста внутри UILabel, просто используйте ограничение ≥ для данной метки, чтобы изменить его размер.

 enter image description here

Это наиболее элегантное решение с использованием Auto Layout. Не забудьте установить numberOfLines на ноль.

37
Nikola Milicevic

Вы можете использовать UITextView вместо UILabel:
Снимите флажок «Прокрутка включена»
Снимите флажок "Редактируемый"
Снимите флажок «Выбираемый»
Установить цвет фона на ClearColor

32
arturdev

У меня была такая же проблема, и вот как я ее решил. Я только что отредактировал базовую линию в Инспекторе атрибутов для метки. Установите его в «Выровнять центры».

 Setting baseline to Align Centers

8
Oyvkva

Вместо этого я изменил Константу нижнего пространства на приоритет @ 250 и решил свою проблему. И мой ярлык имеет постоянную высоты с <= константой

7
Felipe FMMobile

Вы бы сделали это, удалив минимальную высоту.

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

4
Wain

Существует простое решение для случаев, когда высота метки не обязательно должна быть постоянной: поместите свой Label в Stack View. Обязательно добавьте ведущие и конечные константы в Stack View. Вот скриншот того, как это сделать в раскадровке:

 enter image description here

1
Alexander Poleschuk

Я использовал решение @Daniel Golasko, и всякий раз, когда текст внутри UILabel был длиннее, чем мог содержать UILabel, текст начинал двигаться вниз, а не выравниваться по верху.

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

    [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),MIN(ceilf(labelStringSize.height), self.frame.size.height))];
1
ezchen

Swift 4

Вы должны создать подкласс UILabel и переопределить отображение текста.

class UITopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        guard let string = text else {
            super.drawText(in: rect)
            return
        }

        let size = (string as NSString).boundingRect(
            with: CGSize(width: rect.width, height: .greatestFiniteMagnitude),
            options: [.usesLineFragmentOrigin],
            attributes: [.font: font],
            context: nil).size

        var rect = rect
        rect.size.height = size.height.rounded()
        super.drawText(in: rect)
    }
}
1
dimpiax

У меня была похожая проблема, где было 3 ярлыка. Средняя метка может иметь гораздо более длинный текст, чем две другие, поэтому ее высота может вырасти намного больше. 

Как это:

 enter image description here

Я установил ограничение нижнего пространства средней метки на> = нижняя метка.

 enter image description here

Это решило мою проблему.

1
Pætur Magnussen

Автоматическая разметка работает только с краями/размерами контроллера, а не с контентом контроллеров. Поэтому не рекомендуется использовать автоматическую разметку для отображения текста надписи в верхней части первой строки .. По моему мнению, sizetofit - лучший вариант для этого. так.

1
EI Captain v2.0
  @IBInspectable var alignTop: Bool = false

  func setAlignTop() {
    let text = self.text!
    let lines = text.characters.split(separator: "\n").count
    if lines < self.numberOfLines {
      var newLines = ""
      for _ in 0..<(self.numberOfLines - lines) {
        newLines = newLines.appending("\n ")
      }
      self.text! = text.appending(newLines)
    }
  }

  override var text: String? {
    didSet {
      if alignTop {
        self.setAlignTop()
      }
    }
  }
0
hojin

Вы можете попробовать, если кнопка [button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];

Правка : 

Вы можете попробовать это, если хотите использовать только метку:

https://stackoverflow.com/a/11278660/1223897

0
Yuvrajsinh

использовать это мой класс, вы можете изменить текст alignment на contentMode

поддерживаемый регистр: .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight

Swift4

import Foundation
import UIKit

@IBDesignable
class UIAlignedLabel: UILabel {

    override func drawText(in rect: CGRect) {
        if let text = text as NSString? {
            func defaultRect(for maxSize: CGSize) -> CGRect {
                let size = text
                    .boundingRect(
                        with: maxSize,
                        options: NSStringDrawingOptions.usesLineFragmentOrigin,
                        attributes: [
                            NSAttributedStringKey.font: font
                        ],
                        context: nil
                    ).size
                let rect = CGRect(
                    Origin: .zero,
                    size: CGSize(
                        width: min(frame.width, ceil(size.width)),
                        height: min(frame.height, ceil(size.height))
                    )
                )
                return rect

            }
            switch contentMode {
            case .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight:
                let maxSize = CGSize(width: frame.width, height: frame.height)
                var rect = defaultRect(for: maxSize)
                switch contentMode {
                    case .bottom, .bottomLeft, .bottomRight:
                        rect.Origin.y = frame.height - rect.height
                    default: break
                }
                switch contentMode {
                    case .right, .topRight, .bottomRight:
                        rect.Origin.x = frame.width - rect.width
                    default: break
                }
                super.drawText(in: rect)
            default:
                super.drawText(in: rect)
            }
        } else {
            super.drawText(in: rect)
        }
    }

}
0
EvGeniy Ilyin

Вот усовершенствование решения Swift 3 от Daniel Galasko (здесь вы также можете установить максимальный номер строки без смещения вверху):

import UIKit

@IBDesignable class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelString = stringTextAsNSString.boundingRect(with: CGSize(width: frame.width, height: .greatestFiniteMagnitude),
                    options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
            super.drawText(in: CGRect(x: 0, y: 0, width: frame.width, height: ceil(labelString.size.height) > frame.height ? frame.height : ceil(labelString.size.height)))
        } else {
            super.drawText(in: rect)
        }
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.black.cgColor
    }
}
0
Onno Eberhard

Для меня я не установил ограничение по высоте, текст всегда растет сверху метки . Ограничения для этой метки: top, left, right . Кстати, моя метка имеет фиксированную линию цифры, так что не стоит беспокоиться о высоте.

0
Xiang LI