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


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

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

image representing a UILabel with vertically-centered text


1986
2018-06-28 08:54


起源




答案:


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

这是快速简便的方法:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


如果您的文本较长的标签将生成多行,请进行设置 numberOfLines 至 0 (零表示无限数量的行)。

    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


注意 sizeToFit 将尊重您的初始标签的最小宽度。如果您从100宽的标签开始并致电 sizeToFit 在它上面,它会给你一个(可能很高)标签,宽度为100(或更小)。您可能希望在调整大小之前将标签设置为所需的最小宽度。

Correct label alignment by resizing the frame width

其他一些注意事项:

是否 lineBreakMode 受到尊重取决于它是如何设置的。 NSLineBreakByTruncatingTail (默认值)后会被忽略 sizeToFit,以及其他两种截断模式(头部和中部)。 NSLineBreakByClipping 也被忽略了。 NSLineBreakByCharWrapping 像往常一样工作。框架宽度仍然缩小以适合最右边的字母。


马克·阿梅里 在评论中使用自动布局修复了NIB和故事板:

如果您的标签作为子视图包含在笔尖或故事板中 view 一个使用autolayout的ViewController,然后把你的 sizeToFit 打电话给 viewDidLoad 将无法正常工作,因为autolayout大小和位置后的子视图 viewDidLoad 被调用并将立即撤消你的影响 sizeToFit 呼叫。但是,打电话 sizeToFit 从内部 viewDidLayoutSubviews   工作。


我的原始答案(后代/参考):

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

2563
2018-06-28 10:36



你需要删除autolayout - hungbm06
这是解决问题的简单方法: stackoverflow.com/a/26632490/636559 - AboulEinein
如果使用自动布局和故事板,则选中“在构建时删除”选项添加约束将有所帮助 - JK ABC
如果你需要这个 adjustsFontSizeToFitWidth 然后使用sizeToFit然后将标签的框架设置为0,0,theWidthYouWant,label.frame.size.height(这是由sizeToFit确定的新高度)然后应用 adjustsFontSizeToFitWidth - Albert Renshaw
这个答案是不必要的复杂,它使用“周围的字”。请参阅下面的建议,只需更改垂直内容拥抱优先级。不需要任何代码...... - beetree


  1. 设置新文本:

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

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

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. 呼叫 sizeToFit 减少框架大小,使内容适合:

    [myLabel sizeToFit]
    

现在,标签框架的高度和宽度足以适合您的文字。左上角应保持不变。我只用左上对齐的文本测试了这个。对于其他对齐,您可能必须在之后修改框架。

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


315
2017-08-27 16:24



嘿Ben,我只是再次看了我的旧代码,并用必要的正确步骤更新了我的答案。 - Jakob Egger
这对我来说很好。我设置了UILabel的尺寸,并在IB中将numberOfLines更改为0,然后设置了名为[myLabel sizeToFit]的文本。 - Dan Ellis
在Attr中设置行数后,对我来说非常适合。检查员 - d2burke
如果行数超过1,则不起作用 - Tom
当您需要两行标签时,它不起作用,但文本需要更多行。 - Jose Manuel Abarca Rodríguez


参考扩展解决方案:

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也应该用a更新 @" \n@%" 代替 "\n@%" (循环初始化必须替换为“for(int i = 0 ...”)。

以下扩展适用于我:

// -- 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 alignTop]; 要么 [yourLabel alignBottom]; 在每个yourLabel文本分配之后。


151
2017-09-09 13:01



@ D.S。我注意到你正在补充 VerticalAlign 在括号之后 @implementation UILabel。作为Objective-C的新手,我之前没有遇到过这种语法。这个叫什么? - Julian
太棒了,不了解类别,这让我更加欣赏Objective-c语言。学习更多语言对于成为优秀的程序员非常重要。 - JeroenEijkhof
给了一个upvote。但如果您不知道线路的数量是不利的,那么这将不起作用 - Tjirp
我要显示3行文本并将文本对齐到顶部。那么,我是否要将行数设置为3.当我将其设置为3时,如果文本较少(适合一行),我会看到“...”。如何避免这种“......” - Satyam
我将行设置为2但是对于alignTop或alignBottom没有任何区别,我缺少什么? label = [[UILabel alloc] init]; label.numberOfLines = 2; label.frame = CGRectMake(0,TABS_HEIGHT-25,self.frame.size.width,25); label.font = [UIFont fontWithName:@“Arial”size:10]; label.textAlignment = UITextAlignmentCenter; [label alignTop]; - htafoya


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

如果你切换到使用 UITextView,您可以关闭所有滚动视图属性以及启用用户交互...这将强制它更像标签。

enter image description here


126
2017-10-05 12:46



如果将许多UILabel转换为文本视图,则不确定这将如何影响性能。 - ninjaneer
此线程上的所有其他解决方案在iOS 7中无效(无论出于何种原因)。但只是使用一个 UITextView 立刻给了我想要的结果。 - Clifton Labrum
这是一个解决方法,它仍然需要一些调整才能使它看起来真实,但实际上这是我看到的最简单的无代码解决方案,竖起大拇指。 - Itai Spector
我喜欢这个解决方案。当然,可能存在性能问题等等,对于一个相对简单的视图上的简单标签,这对于我需要的东西是完美的(我不会注意到任何性能影响) - JCutting8
这种方法的一个小缺点是它会在文本中引入额外的内在填充。快速解决方法是引入负面约束。 - Sira Lam


没有麻烦,没有大惊小怪

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

}

80
2018-05-21 07:47



快速版本对我没有任何副作用!做得好! - l.vasilev
这里可能是最好的答案,适用于所有场景。如果label在UITableviewCell中,则sizeToFit不起作用。干得好。 - rajat chauhan
伟大的人 - anoop4real


就像上面的答案,但它不是很正确,或者很容易打入代码,所以我清理了一下。将此扩展名添加到它自己的.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];

76
2018-03-04 02:44



有人想添加Swift 3版本吗? - Duncan Groenewald


更快(更脏)的方法是将UILabel的换行模式设置为“Clip”并添加固定数量的换行符。

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

此解决方案不适用于所有人 - 特别是,如果您仍希望在字符串末尾显示“...”,如果它超出您显示的行数,则需要使用其中一个更长的代码 - 但在很多情况下,这将为您提供所需的。


66
2018-04-18 21:08



将换行模式设置为'clip'似乎搞乱了标签的自动调整大小。使用 UILineBreakModeWordWrap 代替。 - Niels van der Rest
并且更好地添加空格“\ n \ n” - djdance