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

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


当前回答

我已经使用了上面的很多方法,只是想添加一个快速而肮脏的方法:

myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];

确保字符串中的换行数将导致任何文本填充可用的垂直空间,并将UILabel设置为截断任何溢出的文本。

因为有时候足够好就是足够好。

其他回答

为了防止对任何人都有帮助,我也遇到了同样的问题,但只需从使用UILabel切换到使用UITextView就可以解决这个问题。我很欣赏这并不是每个人都适合的,因为功能有点不同。

如果您切换到使用UITextView,则可以关闭所有滚动视图财产以及启用用户交互。。。这将迫使它更像一个标签。

无法在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;

如果可以选择创建自己的自定义视图,可以执行以下操作:

- (void)drawRect:(CGRect)rect
{
    CGRect bounds = self.bounds;
    [self.textColor set];
    [self.text drawInRect:bounds
                 withFont:self.font
            lineBreakMode:UILineBreakModeTailTruncation
                alignment:self.textAlignment];
}

对于那些使用自定义表单元格试图解决此问题的人,请将其添加到自定义表单元格类中:

斯威夫特2.2:

override func layoutSubviews() {
    labelName.sizeToFit()
}

这解决了我的问题。

这是一个旧的解决方案,在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