在 UILabel 中将文本垂直对齐到顶部

Vertically align text to top within a UILabel

提问人:Stefan 提问时间:6/28/2009 最后编辑:nevan kingStefan 更新时间:9/9/2021 访问量:759732

问:

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

如何垂直对齐文本以始终位于顶部?UILabel

image representing a UILabel with vertically-centered text

iOS Cocoa-Touch UIKIT UILABEL 文本对齐

评论

0赞 liushuaikobe 12/24/2020
查看 stackoverflow.com/a/41367948/1108052

答:

2777赞 nevan king 6/28/2009 #1

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

以下是执行此操作的快速简便方法:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


如果您的标签包含较长的文本,该文本将产生多行,请设置为(此处为零表示无限行数)。numberOfLines0

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with 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];

enter image description here

标签的大小仍为固定的左上角。您可以将原始标签的宽度保存在变量中,并在 之后进行设置,或者为其指定一个固定的宽度以应对这些问题: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;

label alignment


请注意,这将遵循初始标签的最小宽度。如果你从一个 100 宽的标签开始并调用它,它会给你一个 100(或更小)宽度的(可能非常高)的标签。在调整大小时,您可能希望将标签设置为所需的最小宽度。sizeToFitsizeToFit

Correct label alignment by resizing the frame width

其他一些需要注意的事项:

是否受到尊重取决于它的设置方式。 (默认值)在 之后被忽略,其他两种截断模式(head 和 middle)也是如此。 也被忽略。 照常工作。框架宽度仍变窄以适合最右边的字母。lineBreakModeNSLineBreakByTruncatingTailsizeToFitNSLineBreakByClippingNSLineBreakByCharWrapping


Mark Amery 在评论中给出了使用自动布局的 NIB 和 Storyboard 的修复:

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


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

这使用该方法来计算适合字符串所需的帧高度,然后设置原点和宽度。NSStringsizeWithFont:constrainedToSize: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;

评论

12赞 hungbm06 10/22/2014
您需要删除自动布局
4赞 AboulEinein 10/29/2014
以下是解决问题的简单方法:stackoverflow.com/a/26632490/636559
3赞 beetree 1/23/2015
这个答案不必要地复杂,它使用了“周围这个词”。请参阅下面的建议,即简单地更改垂直内容拥抱优先级。不需要任何代码...
1赞 turingtested 2/1/2016
[myLabel sizeToFit] 在 UITableViewCells 中不起作用,因为此处的标签被重复使用,并且新文本可能不适合。
2赞 orafaelreis 1/27/2017
您仍然可以使用 AutoLayout 和约束,但要确保 [高度] 不会固定。例如:将 Left、Top 和 Right 设置为等于 8px,但将 Bottom 设置为“大于或等于”8px。它会对 iOS 说,让我的 sizeToFit 决定我的标签的更好高度。
27赞 Walty Yeung 1/30/2010 #2

我花了一段时间阅读代码,以及介绍页面中的代码,发现他们都试图修改标签的帧大小,这样就不会出现默认的中心垂直对齐方式。

但是,在某些情况下,我们确实希望标签占据所有这些空间,即使标签确实有如此多的文本(例如,高度相等的多行)。

在这里,我使用了另一种方法来解决这个问题,只需在标签末尾添加换行符即可(请注意,我实际上继承了 ,但这不是必需的):UILabel

CGSize fontSize = [self.text sizeWithFont:self.font];

finalHeight = fontSize.height * self.numberOfLines;
finalWidth = size.width;    //expected width of label

CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];

int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

for(int i = 0; i < newLinesToPad; i++)
{
    self.text = [self.text stringByAppendingString:@"\n "];
}
83赞 BadPirate 3/4/2010 #3

就像上面的答案一样,但它不太正确,或者很容易进入代码,所以我清理了一下。将此扩展名添加到它自己的 .h 和 .m 文件中,或者直接粘贴到您打算使用它的实现的正上方:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end


@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i<= newLinesToPad; i++)
    {
        self.text = [self.text stringByAppendingString:@" \n"];
    }
}

- (void)alignBottom
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i< newLinesToPad; i++)
    {
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
    }
}
@end

然后,要使用,请将您的文本放入标签中,然后调用适当的方法将其对齐:

[myLabel alignTop];

[myLabel alignBottom];

评论

0赞 tdios 12/19/2019
sizeWithFont 已弃用
72赞 Purple Ninja Girl 4/19/2010 #4

实现此目的的更快(也更脏)的方法是将 UILabel 的换行模式设置为“剪辑”并添加固定数量的换行符。

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];

此解决方案并不适合所有人 - 特别是,如果您仍想显示“...”在字符串的末尾,如果它超过了你显示的行数,你将需要使用较长的代码之一 - 但对于很多情况,这将为你提供你需要的东西。

评论

3赞 Niels van der Rest 3/23/2011
将换行模式设置为“剪辑”似乎会扰乱标签的自动调整大小。请改用。UILineBreakModeWordWrap
0赞 djdance 1/16/2016
并更好地添加空格“ \n \n ”
345赞 Jakob Egger 8/28/2010 #5
  1. 设置新文本:

    myLabel.text = @"Some Text"
    
  2. 将行设置为 0(自动):maximum number

    myLabel.numberOfLines = 0
    
  3. 将标签的框架设置为最大尺寸:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. 调用以减小帧大小,使内容刚好适合:sizeToFit

    [myLabel sizeToFit]
    

标签框架现在刚好足够高和宽,可以容纳您的文本。左上角应保持不变。我只用左上角对齐的文本对此进行了测试。对于其他对齐方式,您可能需要在之后修改框架。

此外,我的标签还启用了自动换行功能。

评论

0赞 Dan 7/15/2011
这对我来说效果很好。我设置了我的 UILabel 的尺寸,并在 IB 中将 numberOfLines 更改为 0,然后在设置名为 [myLabel sizeToFit] 的文本后。
0赞 d2burke 3/10/2012
在 Attr 中设置行数后,对我来说效果很好。检查员
0赞 Tom 2/12/2014
在行数超过 1 的情况下不起作用
0赞 Jose Manuel Abarca Rodríguez 2/7/2015
当您想要两行的标签,但文本需要更多行时,它不起作用。
164赞 Dmitri Sologoubenko 9/9/2010 #6

参考扩展解决方案:

for(int i=1; i< newLinesToPad; i++) 
    self.text = [self.text stringByAppendingString:@"\n"];

应替换为

for(int i=0; i<newLinesToPad; i++)
    self.text = [self.text stringByAppendingString:@"\n "];

每添加一个换行符都需要额外的空间,因为 iPhone 的尾随回车符似乎被忽略了:(UILabels

同样,alignBottom 也应该用 in 代替 (因为循环初始化也必须替换为 “for(int i=0......)”。@" \n@%""\n@%"

以下扩展对我有用:

// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end

// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [self.text stringByAppendingString:@"\n "];
}

- (void)alignBottom {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end

然后在每次 yourLabel 文本分配后调用 或。[yourLabel alignTop];[yourLabel alignBottom];

评论

0赞 Julian 5/13/2011
@D.S.我注意到您在括号之间添加。作为 Objective-C 的新手,我以前从未遇到过这种语法。这叫什么?VerticalAlign@implementation UILabel
0赞 JeroenEijkhof 5/26/2011
太棒了,不知道类别,这让我对 Objective-c 语言有了更多的了解。学习更多的语言对于成为一名优秀的程序员非常重要。
0赞 Tjirp 11/30/2011
投了赞成票。但是 IIRC 如果您不知道行数,这将不起作用,这是一个缺点
0赞 Satyam 12/11/2011
我必须显示 3 行文本并将文本与顶部对齐。那么,我必须将行数设置为 3 吗?当我将其设置为 3 时,我看到“...”如果文本较少(适合一行)。如何避免这个“......”
1赞 timgcarlson 4/2/2014
我发布了这个类别的编辑,希望它能很快获得批准。方法和 sizeWithFont: 在 iOS7 中均已弃用。此外,此类别仅适用于 numberOfLines 大于 0 的标签。sizeWithFont:constrainedToSize:lineBreakMode:
14赞 Johnus 9/14/2010 #7

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

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

希望对某人有所帮助!

20赞 user486646 12/14/2010 #8

我采纳了这里的建议,并创建了一个可以包装 UILabel 的视图,并调整其大小并设置行数,使其顶部对齐。简单地将 UILabel 作为子视图:

@interface TopAlignedLabelContainer : UIView
{
}

@end

@implementation TopAlignedLabelContainer

- (void)layoutSubviews
{
    CGRect bounds = self.bounds;

    for (UILabel *label in [self subviews])
    {
        if ([label isKindOfClass:[UILabel class]])
        {
            CGSize fontSize = [label.text sizeWithFont:label.font];

            CGSize textSize = [label.text sizeWithFont:label.font
                                     constrainedToSize:bounds.size
                                         lineBreakMode:label.lineBreakMode];

            label.numberOfLines = textSize.height / fontSize.height;

            label.frame = CGRectMake(0, 0, textSize.width,
                 fontSize.height * label.numberOfLines);
        }
    }
}

@end
5赞 sean woodward 12/16/2010 #9

我采纳了 dalewking 的建议,并添加了一个 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)); 
        }
    }
}
11赞 Nir Pengas 3/1/2011 #10

对于任何阅读本文的人来说,因为标签内的文本不是垂直居中,请记住,某些字体类型的设计并不相同。例如,如果您创建一个 Zapfino 大小为 16 的标签,您会看到文本在垂直方向上并不完全居中。

但是,使用 Helvetica 将使您的文本垂直居中。

评论

0赞 Amit Singh 5/6/2013
许多自定义字体不是垂直居中对齐的。UILabel 或 UITextView 始终垂直居中对齐。无需考虑 iOS 编程中的垂直对齐。
29赞 firestoke 5/23/2011 #11

我写了一个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

35赞 Martin Wickman 7/14/2011 #12

创建 UILabel 的子类。像魅力一样工作:

// TopLeftLabel.h

#import <Foundation/Foundation.h>

@interface TopLeftLabel : UILabel 
{
}

@end

// TopLeftLabel.m

#import "TopLeftLabel.h"

@implementation TopLeftLabel

- (id)initWithFrame:(CGRect)frame 
{
    return [super initWithFrame:frame];
}

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines 
{
    CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];    
    textRect.origin.y = bounds.origin.y;
    return textRect;
}

-(void)drawTextInRect:(CGRect)requestedRect 
{
    CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:actualRect];
}

@end

正如这里所讨论的。

47赞 sebastian friedrich 8/4/2011 #13

创建新类

标签顶部对齐

.h 文件

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

.m 文件

#import "KwLabelTopAlign.h"


@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect {
    int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
    if(rect.size.height >= lineHeight) {
        int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
        int yMax = textHeight;
        if (self.numberOfLines > 0) {
            yMax = MIN(lineHeight*self.numberOfLines, yMax);    
        }

        [super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
    }
}

@end

编辑

下面是一个更简单的实现,它执行相同的操作:

#import "KwLabelTopAlign.h"

@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect
{
    CGFloat height = [self.text sizeWithFont:self.font
                            constrainedToSize:rect.size
                                lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    [super drawTextInRect:rect];
}

@end

评论

0赞 SnakE 2/12/2013
+1 为真实答案。与解决方案不同的是,这实际上使任何文本都放在顶部,即使您动态地将较短的文本替换为较长的文本,反之亦然。sizeToFitUILabel
6赞 jcjimenez 8/17/2011 #14

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

- (void)drawRect:(CGRect)rect
{
    CGRect bounds = self.bounds;
    [self.textColor set];
    [self.text drawInRect:bounds
                 withFont:self.font
            lineBreakMode:UILineBreakModeTailTruncation
                alignment:self.textAlignment];
}
8赞 Sulthan 9/28/2011 #15

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

我的解决方案:

  1. 我自己拆分行(忽略标签换行设置)
  2. 自己画线(忽略标签对齐)

@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
165赞 jowie 10/5/2011 #16

以防万一它对任何人都有任何帮助,我遇到了同样的问题,但只需从使用切换到使用即可解决问题。我很欣赏这并不适合所有人,因为功能有点不同。UILabelUITextView

如果切换到 using ,则可以关闭所有“滚动视图”属性以及“启用用户交互...”。这将迫使它表现得更像一个标签。UITextView

enter image description here

评论

1赞 ninjaneer 11/10/2013
不确定如果将许多 UILabel 转换为文本视图,这将如何影响性能。
2赞 Clifton Labrum 4/29/2014
此线程上的所有其他解决方案在 iOS 7 中都对我不起作用(无论出于何种原因)。但简单地使用 a 立即给了我想要的结果。UITextView
1赞 Itai Spector 9/11/2015
这是一种解决方法,它仍然需要一些调整才能使其看起来真实,但实际上这是我看到的最简单的无代码解决方案,竖起大拇指。
1赞 JCutting8 1/17/2016
我喜欢这个解决方案。当然,可能存在性能问题等,对于相对简单的视图上的简单标签,这非常适合我需要的东西(而且我没有注意到任何性能影响)
2赞 Sira Lam 2/27/2018
这种方法的一个小缺点是它会为文本引入额外的内在填充。快速解决方法是引入负约束。
42赞 bearMountain 1/3/2012 #17

enter image description here

在Interface Builder中

  • 设置为最大可能文本的大小UILabel
  • 在属性检查器中设置为“0”Lines

在代码中

  • 设置标签的文本
  • 调用您的标签sizeToFit

代码片段:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];

评论

0赞 eselk 10/2/2012
效果很好,除了在我的情况下,我需要将行设置为 2 - 在 UITableViewCell 中有一个 UILabel,设置为 0 使其重叠,但设置为 2 有效(单元格有足够的空间容纳 2 行)
64赞 ivanzoid 2/10/2012 #18

您可以使用具有垂直对齐选项的代替:UILabelUITextField

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction

评论

7赞 David James 12/30/2014
注意:UITextField 只允许一行文本。
3赞 CedricSoubrie 7/26/2017
要完成@DavidJames注释:UITextView 会更合适
8赞 geekay 3/13/2012 #19

只要你不做任何复杂的任务,你就可以使用代替 .UITextViewUILabels

禁用滚动。

如果希望文本完全显示,则仅显示用户和方法sizeToFitsizeThatFits:

5赞 vbwx 4/10/2012 #20

我也在研究那个特定的问题,所以我采纳了 D.S.nevan king 的想法,基本上将它们组合成一个实现垂直对齐属性的子类,这也允许您多次更改对齐方式。它借用了类型,还支持 .UIControlContentVerticalAlignmentUIControlContentVerticalAlignmentFill

据我所知,在垂直对齐方面似乎毫无用处,因此在此子类中,应用垂直对齐时始终设置为 0。 此外,如果您想要多行文本标签,您仍然需要自己设置。numberOfLineslineBreakMode

就是这样:GitHub 上的 QALabel

6赞 atul awasthi 5/16/2012 #21

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

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

146赞 jasongregori 5/21/2012 #22

没有烦恼,没有大惊小怪

@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

没有 muss,没有 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)
    }

}

评论

0赞 l.vasilev 3/14/2017
快速版本对我有用,没有任何副作用!干得好!
10赞 rajat chauhan 4/3/2018
可能是这里最好的答案,适用于所有场景。如果标签位于 UITableviewCell 中,则 sizeToFit 不起作用。干得好。
1赞 John Pitts 8/13/2021
亲爱的苹果,让文本自动进入左上角应该不难。也就是说,这里的答案很好@jasongregori。尝试了拥抱概念和顶级答案,niether 适用于 CollectionViewCell 标签。UILabel 的自定义类是解决方案。
1赞 John Pitts 8/13/2021
对于那些不了解自定义类概念的人,请使用以下方法修复上述答案: 1. 在项目中创建一个新的 Swift 文件。COMMAND + N. 2.为自定义 UILabel 类插入下图所示的代码。不要忘记将 UIKit 导入到此文件中,否则您将在此代码上看到到处都是红色,从 XCode 无法识别“UILabel”作为类类型开始。4. 另外,不要忘记进入标签的 Identity Inspector 切换自定义类并找到“VerticalTopAlignLabel”或您命名的任何名称。
10赞 jrc 7/3/2012 #23

子类 UILabel 并约束绘图矩形,如下所示:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];
    rect.size.height = MIN(rect.size.height, sizeThatFits.height);

    [super drawTextInRect:rect];
}

我尝试了涉及换行符填充的解决方案,但在某些情况下遇到了不正确的行为。根据我的经验,如上所述约束绘图矩形比弄乱 .numberOfLines

P.S. 你可以想象一下,以这种方式轻松支持 UIViewContentMode:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];

    if (self.contentMode == UIViewContentModeTop) {
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }
    else if (self.contentMode == UIViewContentModeBottom) {
        rect.origin.y = MAX(0, rect.size.height - sizeThatFits.height);
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }

    [super drawTextInRect:rect];
}
14赞 Code Roadie 9/18/2012 #24

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

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

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

因为有时足够好就足够好

评论

0赞 Rambatino 9/15/2014
但是,鉴于 iOS 设备的屏幕尺寸高度存在差异,因此需要有可变数量的“\n”来解释 uilabel 高度的变化(这是可能的)。因此,从长远来看,这种方法并不是特别有用。
0赞 Code Roadie 9/16/2014
注意:“快速而肮脏”不是“永远完美的解决方案”。只是说'。
2赞 Séraphin Hochart 3/28/2015
@CodeRoadie 快速而肮脏对我来说是诀窍,但我在真正的答案中遇到了一些布局问题。我可以用“正确的方式”去做,但谢谢你为我节省了一些时间!
0赞 Code Roadie 8/17/2015
@dGambit请注意:“又快又脏"
1赞 yano 12/1/2015
我最近在动态加载视图时学到的一点是,它可以调用以支持文本输入。这可能会导致 UI 线程出现重大延迟,因此此方法的性能要高得多!UITextViewdlopen
4赞 SunnyChattha 10/2/2012 #25

有两种方法可以解决此问题。一是

[mylabel setNumberOfLines:0];
[mylabel sizeToFit];

但对于这种方法来说,第二种方法更可靠,即,

 CGSize sizeToFit = [label.text sizeWithFont:label.font constrainedToSize:maxSize lineBreakMode:label.lineBreakMode];
 [mylabel setFrame:CGRectMake(mylabel.frame.origin.x, mylabel.frame.origin.y, sizeToFit.width, sizeToFit.height)];

输入“\n”并不是一件好事,但是是的,如果您知道要显示的数据的约束和大小,它可能工作得很好,但如果文本长于标签的大小,则无法扩展。第二种方式最终根据要显示的文本的大小设置框架。

55赞 David Greco 10/17/2012 #26

我已经为此苦苦挣扎了很长时间,我想分享我的解决方案。

这将为您提供一个自动将文本缩小到 0.5 比例并将文本垂直居中。这些选项在 Storyboard/IB 中也可用。UILabel

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];

评论

0赞 Ashok 3/10/2015
在提供的所有答案中,它的工作是完美的。谢谢@David Greco。除了这些属性外,如果我们将 adjustsFontSizeToFitWidth 设置为 YES,则文本将适合框架,而无需修改标签的框架。
-1赞 Gaurav 11/11/2012 #27

试试这个!!太手动了,但对我来说很完美。

[labelName setText:@"This is just a demo"];

NSMutableString *yourString1= @"This is just a demo";


// breaking string
labelName.lineBreakMode=UILineBreakModeTailTruncation;
labelName.numberOfLines = 3;


CGSize maximumLabelSize1 = CGSizeMake(276,37); // Your Maximum text size

CGSize expectedLabelSize1 = [yourString1 sizeWithFont:labelName.font
                                    constrainedToSize:maximumLabelSize1
                                        lineBreakMode:labelName.lineBreakMode];

[labelName setText:yourString1];


CGRect newFrame1 = labelName.frame;
if (expectedLabelSize1.height>=10)
{
    newFrame1.size.height = expectedLabelSize1.height;
}

labelName.frame = newFrame1;
2赞 cohen72 1/31/2013 #28

在发布的所有其他解决方案的基础上,我创建了一个简单的小 UILabel 子类,该子类将在设置其 alignment 属性时为您处理垂直对齐。这也将在方向更改时更新标签,将高度限制为文本,并将标签的宽度保持在原始大小。

.h

@interface VAlignLabel : UILabel
@property (nonatomic, assign) WBZVerticalAlignment alignment;
@end


.m

 -(void)setAlignment:(WBZVerticalAlignment)alignment{

    _alignment = alignment;

    CGSize s = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(self.frame.size.width, 9999) lineBreakMode:NSLineBreakByWordWrapping];

    switch (_alignment)
    {
        case wbzLabelAlignmentVerticallyTop:
            self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, s.height);
            break;
        case wbzLabelAlignmentVerticallyMiddle:
            self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + (self.frame.size.height - s.height)/2, self.frame.size.width, s.height);
            break;
        case wbzLabelAlignmentVerticallyBottom:
            self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + (self.frame.size.height - s.height), self.frame.size.width, s.height);
            break;
        default:
            break;
    }
}

-(void)layoutSubviews{
    [self setAlignment:self.alignment];
}
3赞 KarenAnne 3/15/2013 #29

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

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

返回的尺寸将最适合您的标签内容。如果标签的高度与其内容相符,则将内容放置在标签的中心不会有问题。

3赞 Ramesh Muthe 3/25/2013 #30

此代码可帮助您使文本与顶部对齐,并使标签高度固定文本内容。

使用以下代码的说明

isHeightToChange默认情况下,它是 true,它会自动使标签的高度与文本内容相同。 如果为 false,则使文本与顶部对齐,而不会降低标签的高度。isHeightToChange

#import "DynamicHeightLable.h"

@implementation DynamicHeightLable
@synthesize isHeightToChange;
- (id)initWithFrame:(CGRect)frame 
{
    self = [super initWithFrame:frame];
    if (self)
    {
        // Initialization code.
        self.isHeightToChange=FALSE;//default

    }
    return self;
}
- (void)drawTextInRect:(CGRect)rect
{
    if(!isHeightToChange){
    CGSize maximumLabelSize = CGSizeMake(self.frame.size.width,2500);

    CGFloat height = [self.text sizeWithFont:self.font
                           constrainedToSize:maximumLabelSize
                               lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    }
    [super drawTextInRect:rect];

}
- (void) layoutSubviews
{
    [super layoutSubviews];
       if(isHeightToChange){
     CGRect ltempFrame = self.frame;
    CGSize maximumLabelSize = CGSizeMake(self.frame.size.width,2500);

    CGFloat height = [self.text sizeWithFont:self.font
                           constrainedToSize:maximumLabelSize
                               lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    ltempFrame.size.height = MIN(ltempFrame.size.height, height);

    ltempFrame.size.height=ltempFrame.size.height;
    self.frame=ltempFrame;
       }
}
@end
4赞 mbo42 7/23/2013 #31
yourLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
9赞 phatmann 9/6/2013 #32

如果使用自动布局,请在代码或 IB 中将垂直 contentHuggingPriority 设置为 1000。在 IB 中,您可能必须通过将高度约束的优先级设置为 1 然后将其删除来消除高度约束。

14赞 jjxtra 9/27/2013 #33

FXLabel(在 github 上)通过设置为 来开箱即用。这个组件不是我做的,但它是我经常使用的组件,具有大量功能,并且似乎运行良好。label.contentModeUIViewContentModeTop

6赞 barndog 12/13/2013 #34

我知道这是一篇旧文章,但垂直对齐文本是一个巨大的问题(至少对我来说是这样),我想我应该分享这个解决方案,因为我自己找不到。

在我看来,使用 drawRect 有点贵。使 UILabel 垂直对齐的正确方法是不使用 UILabel。使用 UITextView(多行 UITextField)并观察 content 属性,如下所示:

- (UITextView*)textView{
     if(!_textView){
        UIEdgeInsets insets = UIEdgeInsetsMake(0, 50, 0, 5);
        CGRect frame = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
        _textView = [[UITextView alloc]initWithFrame:UIEdgeInsetsInsetRect(frame, insets)];
        _textView.delegate = self;
        _textView.scrollEnabled = YES;
        _textView.bounces = YES;
        _textView.backgroundColor = [UIColor whiteColor];
        [_textView setUserInteractionEnabled:NO];
        [_textView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
    }
    return _textView;
}

 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:    (NSDictionary *)change context:(void *)context {
UITextView *tv = object;

CGFloat height = [tv bounds].size.height;
CGFloat contentheight;

#ifdef __IPHONE_7_0
    contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;
#else
    contentheight = [tv contentSize].height;
#endif

    switch(self.verticalAlignment) {
        case VerticalAlignmentBottom:{
            CGFloat topCorrect = ([tv bounds].size.height - contentheight);
            topCorrect = (topCorrect <0.0 ? 0.0 : topCorrect);
            tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
        }
        break;
        case VerticalAlignmentMiddle:{
            CGFloat topCorrect = (height - contentheight * [tv zoomScale])/2.0;
            topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
            tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
        }
            break;
        case VerticalAlignmentTop:{
            tv.contentOffset = (CGPoint){.x = 0, .y = 0 };
        }
            break;
        default:
            break;
    }
}

基本上,这里发生的事情是,我们将我们所在的类设置为观察者,使用 NSKeyValueObservingOptionNew 选项查看 contentSize 属性,因此每次内容更改时都会被调用,然后您可以计算偏移量以适当地对齐文本。-(void)observeValueForKeyPath:ofObject:change:context:

我不能把功劳归功于此,最初的想法来自这里。但是,此解决方案不适用于 iOS7。在 SO 周围拖钓了几个小时后,我发现了这一点:iOS 7 垂直对齐修复。关键线是 .由于某种原因,在 iOS 7 中,获取 contentSize 高度不起作用,但这可以修复它。这两种解决方案都不能单独使用,但经过一番修补,我能够将上述解决方案综合在一起。contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;

16赞 petehare 4/29/2014 #35

我发现这个问题的答案现在有点过时了,所以为那里的自动布局爱好者添加这个。

自动布局使这个问题变得非常微不足道。假设我们将标签添加到 ,以下代码将完成此操作:UIView *view

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];

[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];

标签的高度将自动计算(使用 it's),并且标签将沿边缘到边缘水平定位在 的顶部。intrinsicContentSizeview

20赞 Andrew Romanov 8/28/2014 #36

可以使用 TTTAttributedLabel,它支持垂直对齐。

@property (nonatomic) TTTAttributedLabel* label;
<...>

//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;
38赞 Rabindra Nath Nandi 8/8/2015 #37

对于自适应 UI(iOS8 或更高版本),UILabel 的垂直对齐是通过更改属性 =0' 和noOfLines

约束

  1. 调整 UILabel LefMargin、RightMargin 和 Top Margin 约束。

  2. 更改 =1000' 使垂直>水平 .Content Compression Resistance Priority For Vertical

Constraints of UILabel

编辑:

noOfLines=0

而以下约束条件足以达到预期的效果。

enter image description here

评论

0赞 Gabriel 12/2/2016
这真是太棒了。您能解释一下为什么垂直>水平可以完成这项工作吗?谢谢。
8赞 Dara Tith 2/23/2016 #38

在 swift 中,

let myLabel : UILabel!

使标签的文本适合屏幕,并且它位于顶部

myLabel.sizeToFit()

使标签的字体适合屏幕宽度或特定宽度大小。

myLabel.adjustsFontSizeToFitWidth = YES

和一些 textAlignment 用于标签:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified

评论

0赞 velkoon 10/6/2018
只是对 的旧语法进行了语法更改。谢谢![myLabel sizeToFit]
6赞 Alvin George 3/29/2016 #39

斯威夫特 2.0:

在空的 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)
4赞 Elliott Davies 6/14/2016 #40

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

斯威夫特 2.2:

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

这解决了我的问题。

6赞 seggy 10/25/2016 #41

对于 Swift 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
    }
}
41赞 ma11hew28 12/29/2016 #42

用。textRect(forBounds:limitedToNumberOfLines:)

class TopAlignedLabel: UILabel {
  override func drawText(in rect: CGRect) {
    let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
    super.drawText(in: textRect)
  }
}

评论

2赞 Diogo Antunes 10/5/2017
先生,你是神!
5赞 Michael Ochs 1/29/2018
这个答案应该会得到更多的赞成,因为它是迄今为止最好和最干净的解决方案!
1赞 Leo Dabus 12/28/2020
太好了。它引导我朝着正确的方向垂直居中我的标签。
2赞 Onur Şahindur 8/10/2021
非常优雅的解决方案
1赞 vibhor nijhavan 8/16/2022
这对我有用。这应该得到更多的赞成。
104赞 Baig 3/28/2017 #43

使用 Storyboard 的最简单方法:

在 StackView 中嵌入 Label,并在 Attribute Inspector 中设置 StackView 的以下两个属性:

1- 到 ,AxisHorizontal

2 至AlignmentTop

enter image description here

评论

2赞 Daniel Beltrami 8/3/2018
为了获得更好的结果,您可以在 UILabel > View >执行此操作,因为当您只是在 StackView 中嵌入 UILabel 时,StackView 会调整大小以适合 UILabel 的最小大小
0赞 Viktor Kucera 9/10/2018
将该标签放入某个子类(通常就足够了)并让该标签向下增长的好主意。谢谢!UILabelUIViewUIView
1赞 Rocket Garden 4/6/2020
使用选中标签的 Editor->Embed 菜单命令,Xcode 会为您清除标签约束,然后您只需为 StackView 设置约束即可。这种方法最接近于“SwiftUI”布局方法,这就是我发现它的方式。
1赞 Ricardo Barroso 9/9/2021
你不需要 ,只需将 嵌入其中即可。设置约束以占用应增长到的最大空间。然后将 设置为 的顶部、右侧和左侧,并将约束也设置为底部的距离。UIStackViewUILabelUIViewUIViewUILabelUILabelUIView>= 0
0赞 Evgeniy Kleban 12/8/2023
解决了我的问题
3赞 Nuno Gonçalves 6/26/2017 #44

这个问题的简单解决方案...

将标签放在下方。UIStackView

然后,使用“自动布局”将标签的垂直间距设置为零,并将顶部限制为标签的底部。标签不会增长,stackView 会增长。我喜欢这一点的是堆栈视图是非渲染的。所以这并不是真的浪费时间渲染。即使它进行 AutoLayout 计算。

不过,您可能需要使用 ContentHugging 和 Resistance,但这也很简单。

我时不时地用谷歌搜索这个问题,然后回到这里。这一次我有一个我认为最简单的 ideia,我不认为它的表现很糟糕。 我必须说我只是在使用 AutoLayout,并不想打扰计算帧。那只是......呸。

1赞 Ashish 10/27/2017 #45

以下是 Swift 4.0 中的解决方案:

func viewDidLoad() {

    super.viewDidLoad()

    // 20 point top and left margin. Sized to leave 20 pt at right.
    let labelFrame = CGRect(x: 20, y: 20, width: 280, height: 150)
    let myLabel = UILabel(frame: labelFrame)
    myLabel.backgroundColor = UIColor.orange

    let labelText = "I am the very model of a modern Major-General, 
    I've information vegetable, animal, and mineral"
    myLabel.text = labelText

    // Tell the label to use an unlimited number of lines
    myLabel.numberOfLines = 0
    myLabel.sizeToFit()

    view.addSubview(myLabel) // add label
}
5赞 BennyTheNerd 3/8/2018 #46

(截至2018年3月7日)

斯威夫特 4

let maxFrameHeight = 75

myLabel = UILabel()
myLabel.frame = CGRect(x: 9, y: 9, width: 126, height: maxFrameHeight)
myLabel.text = "my labels text displayed"
myLabel.numberOfLines = 0

myLabel.sizeToFit()
let newFrameHeight = myLabel.frame.size.height
let safeNewHeight = min(newFrameHeight, maxFrameHeight)

myLabel.frame = CGRect(x: 9, y: 9, width: 126, height: safeNewHeight)

这将获得预期的结果,并且它将确保 UILabel 的新高度不会超过您期望的此标签的某个最大高度。

评论

1赞 Ivan Carosati 3/9/2018
它运行良好,但您必须设置!numberOfLines = 0
37赞 Jack Tiong 5/19/2018 #47

我在我的应用程序中所做的是将 UILabel 的 line 属性设置为 0,并创建 UILabel 的底部约束并确保将其设置为 >= 0,如下图所示。enter image description here

评论

0赞 AndroidDev 6/13/2020
我不知道为什么这不是公认的答案。比现在简单得多。不错的答案!
0赞 Ensar Bayhan 3/9/2021
是的!这就是我一直在寻找的。这应该是公认的答案。
0赞 Brittany 7/27/2021
到目前为止,更好的答案。谢谢!+1
0赞 Ruben Marin 1/31/2019 #48

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

labelHeightConstraint.constant = centerAlignment ? 30 : 15
layoutIfNeeded()
2赞 Mojtaba Hosseini 10/10/2019 #49

SwiftUI界面

在 SwiftUI 中,所有视图通常都是 sizeToFit 其内容,但如果显式使用修饰符,则可以使用框架的参数:framealignment

Text("Text")
    .background(Color.red)
    .frame(width: 100, height: 200, alignment: .top)

此外,如果您使用任何类型的视图来排列视图,它们都有一个类似于 frame 的参数,称为:Stackalignment

ZStack(alignment: .top) {
    Color.red
    Text("Text")
        .background(Color.red)
}
9赞 dimpiax 6/17/2021 #50

斯威夫特 5

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

final class TopAlignedLabel: UILabel {
  override func drawText(in rect: CGRect) {
    super.drawText(in: .init(
      origin: .zero, 
      size: textRect(
        forBounds: rect, 
        limitedToNumberOfLines: numberOfLines
      ).size
    ))
  }
}
2赞 Ricardo Barroso 9/9/2021 #51

您可以通过代码或简单地在情节提要上执行以下操作来解决此问题:

  1. 将行数设置为等于 。UILabel0
  2. 将 .UILabelUIView
  3. 设置约束(顶部、右侧、左侧和底部)以占用应增长到的最大空间。UIViewUILabel
  4. 然后设置到顶部、右侧和左侧,并将 距离设置为底部的约束。UILabelUIView>= 0