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

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


当前回答

这是一个旧的解决方案,在iOS上使用自动布局>=6

我的解决方案:

自行拆分线条(忽略标签换行设置)自己绘制线(忽略标签对齐)


@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

其他回答

我希望有一个标签能够有多行,最小字体大小,并在父视图中水平和垂直居中。我以编程方式将标签添加到视图中:

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

希望这对某人有所帮助!

雨燕5

这里是从左上角开始渲染文本,并保持可能调整的文本大小。

final class TopAlignedLabel: UILabel {
  override func drawText(in rect: CGRect) {
    super.drawText(in: .init(
      origin: .zero, 
      size: textRect(
        forBounds: rect, 
        limitedToNumberOfLines: numberOfLines
      ).size
    ))
  }
}

我编写了一个util函数来实现这个目的。你可以看看:

// 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是由Interface builder创建的,所以我跳过了一些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

在UILabel中,无法垂直对齐文本。但是,您可以使用NSString的sizeWithFont:方法动态更改标签的高度,并根据需要设置其x和y。

您可以使用UITextField。它支持contentVerticalAlignment人员,因为它是UIControl的子类。您必须将其userInteractionEnabled设置为NO,以防止用户在其上键入文本。

无法在UILabel上设置垂直对齐,但可以通过更改标签的框架来获得相同的效果。我把我的标签做成橙色,这样你就能清楚地看到发生了什么。

以下是快速简便的方法:

    [myLabel sizeToFit];


如果您有一个包含多行的较长文本的标签,请将numberOfLines设置为0(此处零表示无限行数)。

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];


更长版本

我将在代码中制作标签,这样您就可以看到发生了什么。您也可以在Interface Builder中设置大部分内容。我的设置是一个基于视图的应用程序,带有我在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的一些限制会影响居中或右对齐的文本。以下是发生的情况:

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

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

标签的大小仍然是固定的左上角。您可以将原始标签的宽度保存在变量中,并在sizeToFit之后进行设置,或者为其设置固定宽度以解决这些问题:

    myLabel.textAlignment = NSTextAlignmentCenter;

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

    CGRect myFrame = myLabel.frame;
    // Resize the frame's 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;


请注意,sizeToFit将尊重初始标签的最小宽度。如果您从一个100宽的标签开始,并在其上调用sizeToFit,那么它将返回一个100(或稍小)宽的标签(可能非常高)。在调整大小之前,您可能需要将标签设置为所需的最小宽度。

需要注意的其他事项:

是否遵守lineBreakMode取决于其设置方式。NSLineBreakByTruncatingTail(默认值)在sizeToFit之后被忽略,其他两种截断模式(头部和中部)也是如此。NSLineBreakByClipping也被忽略。NSLineBreakByCharWrapping照常工作。框架宽度仍然变窄,以适合最右边的字母。


Mark Amery在评论中使用Auto Layout修复了NIB和Storyboards:

如果标签包含在笔尖或情节提要中,作为使用自动布局的ViewController视图的子视图,那么将sizeToFit调用放入viewDidLoad将不起作用,因为在调用viewDidLoad后自动布局将调整子视图的大小和位置,并将立即撤消sizeToFit调用的效果。但是,从viewDidLayoutSubviews内调用sizeToFit将起作用。

我的原始答案(供后人参考):

这使用NSString方法sizeWithFont:consainedToSize: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;