我有一个UILabel,它有两行文字的空间。有时,当文本太短时,此文本会显示在标签的垂直中心。

如何垂直对齐文本,使其始终位于UILabel的顶部?


当前回答

您可以手动更改标签的高度,而不是使用sizeToFit;

CGSize size = [descLabel.text sizeWithFont:descLabel.font constrainedToSize:CGSizeMake(labelWidth, labelHeight)];
CGRect frame = descLabel.frame;
frame.size.height = size.height;    
[yourLabel setFrame:frame];

返回的尺寸将最适合标签的内容。如果标签的高度适合其内容,则内容位于标签中心时不会出现问题。

其他回答

不要大惊小怪

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

}

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

}

可以更灵活地在Interface Builder中为标签设置高度约束,使用IBOutlet将其绑定到代码,并更改高度以在具体的垂直位置显示文本。中心和底部对齐示例:

labelHeightConstraint.constant = centerAlignment ? 30 : 15
layoutIfNeeded()

对于那些因为标签中的文本不是垂直居中而阅读本文的人,请记住,某些字体类型的设计并不相同。例如,如果您创建一个zapfino大小为16的标签,您将看到文本没有完全垂直居中。

然而,使用helvetica会使文本垂直居中。

FXLabel(在github上)通过将label.contentMode设置为UIViewContentModeTop来实现这一点。这个组件不是我制造的,但它是我经常使用的组件,具有大量的功能,而且似乎工作得很好。

我重复了戴莱辛的建议,并添加了一个UIEdgeInset,以允许调整边距。周围环境不错。

- (id)init
{
    if (self = [super init]) {
        contentEdgeInsets = UIEdgeInsetsZero;
    }

    return self;
}

- (void)layoutSubviews
{
    CGRect localBounds = self.bounds;
    localBounds = CGRectMake(MAX(0, localBounds.origin.x + contentEdgeInsets.left), 
                             MAX(0, localBounds.origin.y + contentEdgeInsets.top), 
                             MIN(localBounds.size.width, localBounds.size.width - (contentEdgeInsets.left + contentEdgeInsets.right)), 
                             MIN(localBounds.size.height, localBounds.size.height - (contentEdgeInsets.top + contentEdgeInsets.bottom)));

    for (UIView *subview in self.subviews) {
        if ([subview isKindOfClass:[UILabel class]]) {
            UILabel *label = (UILabel*)subview;
            CGSize lineSize = [label.text sizeWithFont:label.font];
            CGSize sizeForText = [label.text sizeWithFont:label.font constrainedToSize:localBounds.size lineBreakMode:label.lineBreakMode];

            NSInteger numberOfLines = ceilf(sizeForText.height/lineSize.height);

            label.numberOfLines = numberOfLines;
            label.frame = CGRectMake(MAX(0, contentEdgeInsets.left), MAX(0, contentEdgeInsets.top), localBounds.size.width, MIN(localBounds.size.height, lineSize.height * numberOfLines)); 
        }
    }
}