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

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

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

垂直水平居中的UILabel图像

743065 次浏览

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

这里有一个快速和简单的方法来做到这一点:

    [myLabel sizeToFit];

sizeToFit挤压标签


如果你有一个长文本的标签,它会产生多行,设置numberOfLines0(这里的零意味着无限的行数)。

    myLabel.numberOfLines = 0;[myLabel sizeToFit];

长标签文本与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.widthmyFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);myLabel.frame = myFrame;

标签对齐方式


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

通过调整框架宽度来纠正标签对齐

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

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


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

如果您的标签作为使用autolayout的ViewController的view的子视图包含在笔尖或故事板中,那么将sizeToFit调用放入viewDidLoad将不起作用,因为autolayout在调用viewDidLoad后大小和位置子视图,并将立即撤消sizeToFit调用的效果。但是,从viewDidLayoutSubviews内调用sizeToFit可以。


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

这使用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:dateFontconstrainedToSize:maximumSizelineBreakMode:self.dateLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);
self.dateLabel.frame = dateFrame;

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

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

在这里,我使用了另一种方法来解决它,只需将换行符填充到标签的末尾(请注意,我实际上继承了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 "];}

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

一个更快(和更脏)的方法来实现这一点是通过将UILabel的换行符模式设置为“Clip”并添加固定数量的换行符。

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

这个解决方案并不适用于所有人——特别是,如果你仍然想在字符串的末尾显示“…”,如果它超过了你显示的行数,你需要使用一个较长的代码位——但在很多情况下,这会让你得到你需要的。

  1. 设置新文本:

    myLabel.text = @"Some Text"
  2. Set the maximum number of lines to 0 (automatic):

    myLabel.numberOfLines = 0
  3. Set the frame of the label to the maximum size:

    myLabel.frame = CGRectMake(20,20,200,800)
  4. Call sizeToFit to reduce the frame size so the contents just fit:

    [myLabel sizeToFit]

The labels frame is now just high and wide enough to fit your text. The top left should be unchanged. I have tested this only with the top left-aligned text. For other alignments, you might have to modify the frame afterward.

Also, my label has word wrapping enabled.

参考扩展解决方案:

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 "];

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

类似地,也应该用@" \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 labelCGSize 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 labelCGSize 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];后,每个你的标签文本分配。

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

- (void) customInit {// Setup labelself.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 subviewself.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 sizeif (textSize.height > self.frame.size.height) {textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];}
// Drawself.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);self.label.text = text;}[self setNeedsDisplay];}

希望能帮助到别人!

我接受了这里的建议,并创建了一个视图,它可以包装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.fontconstrainedToSize:bounds.sizelineBreakMode:label.lineBreakMode];
label.numberOfLines = textSize.height / fontSize.height;
label.frame = CGRectMake(0, 0, textSize.width,fontSize.height * label.numberOfLines);}}}
@end

我重复了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));}}}

对于任何阅读这篇文章的人,因为你的标签内的文本不是垂直居中的,请记住,一些字体类型不是平等设计的。例如,如果你创建一个zapfino大小为16的标签,你会看到文本不是完美的垂直居中。

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

我写了一个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 heightCGSize 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的子类。像魅力一样工作:

// 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

讨论这里

创建一个新类

标签标题对齐

. 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.fontconstrainedToSize:rect.sizelineBreakMode: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

如果可以选择创建自己的自定义视图,则可以这样做:

- (void)drawRect:(CGRect)rect{CGRect bounds = self.bounds;[self.textColor set];[self.text drawInRect:boundswithFont:self.fontlineBreakMode:UILineBreakModeTailTruncationalignment:self.textAlignment];}

这是一个旧的解决方案,在iOS>=6时使用autolayout

我的解决方案:

  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

如果它对任何人都有帮助,我也遇到了同样的问题,但只要从使用UILabel切换到使用UITextView就可以解决这个问题。我很感激这不适合每个人,因为功能有点不同。

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

在此处输入图像描述

输入图片描述

在界面生成器

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

在你的代码

  • 设置标签的文本
  • 在你的标签上打电话sizeToFit

代码片段:

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

而不是UILabel,您可以使用具有垂直对齐选项的UITextField

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

只要你不做任何复杂的任务,你可以使用UITextView而不是UILabels

禁用滚动。

如果您想完全显示文本,只需用户sizeToFitsizeThatFits:方法

我也在研究那个特定的问题,所以我接受了D. S.内华达国王的想法,基本上将它们组合成一个子类,它实现了垂直对齐属性,这也允许你不止一次更改对齐方式。它借用了UIControlContentVerticalAlignment类型,也支持UIControlContentVerticalAlignmentFill

从我所看到的,numberOfLines在垂直对齐方面似乎是无用的,所以在这个子类中,当应用垂直对齐时,它总是设置为0。此外,您仍然需要自己设置lineBreakMode,以防您想要多行文本标签。

在这里:GitHub上的QALabel

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

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

没有混乱,没有大惊小怪

@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.sizeoptions:NSStringDrawingUsesLineFragmentOrigincontext: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 = rectnewRect.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)}
}

Swift4.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 = rectnewRect.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)}
}

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

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

我尝试了涉及换行符填充的解决方案,在某些情况下遇到了不正确的行为。根据我的经验,像上面那样约束绘图矩形比搞乱numberOfLines更容易。

附注:您可以想象以这种方式轻松支持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];}

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

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

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

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

有两种方法可以解决这个问题

[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"并不是一件好事,但是如果你知道约束和将要显示的数据的大小,它可能工作良好,但如果文本长于标签的大小,则无法扩展。第二种方法最终根据要显示的文本的大小设置框架。

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

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

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

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

[labelName setText:@"This is just a demo"];
NSMutableString *yourString1= @"This is just a demo";

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

CGSize maximumLabelSize1 = CGSizeMake(276,37); // Your Maximum text size
CGSize expectedLabelSize1 = [yourString1 sizeWithFont:labelName.fontconstrainedToSize:maximumLabelSize1lineBreakMode:labelName.lineBreakMode];
[labelName setText:yourString1];

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

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

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

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

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

返回的大小将最适合标签的内容。如果标签的高度与其内容相匹配,则内容定位在标签中心不会有问题。

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

使用下面代码的指令

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

#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.fontconstrainedToSize:maximumLabelSizelineBreakMode: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.fontconstrainedToSize:maximumLabelSizelineBreakMode: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
yourLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;

如果您使用的是autolayout,请在代码或IB中将垂直内容HuggingPriium设置为1000。在IB中,您可能必须通过将高度约束的优先级设置为1然后删除它来删除它。

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

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

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

- (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_0contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;#elsecontentheight = [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上浏览了几个小时后,我发现了这个:iOS7垂直对齐修复。关键行是contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;。出于某种原因,在iOS7中,获取ContentSize高度不起作用,但这解决了它。这两个解决方案都不起作用,但经过一点修补,我能够将上述解决方案综合在一起。

我发现这个问题的答案现在有点过时了,所以为那里的汽车布局粉丝添加这个。

自动布局使这个问题变得非常简单。假设我们将标签添加到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}]];

标签的高度将自动计算(使用它的intrinsicContentSize),并且标签将水平定位在view的顶部。

您可以使用TTT属性标签说明,它支持垂直对齐。

@property (nonatomic) TTTAttributedLabel* label;<...>
//view's or viewController's init method_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;

对于Adaptive UI(iOS8或之后),UILabel的垂直对齐将通过更改属性从StoryBoard设置noOfLines=0'和

制约因素

  1. 调整UILabel左保证金、右保证金和顶保证金约束。

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

UILabel的约束

编辑:

noOfLines=0

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

在此处输入图片描述

在斯威夫特,

let myLabel : UILabel!

使您的标签文本适合屏幕,并在顶部

myLabel.sizeToFit()

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

myLabel.adjustsFontSizeToFitWidth = YES

和一些标签的文本对齐:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified

Swift 2.0:

在空Swift文件中创建常量枚举值。

//  AppRef.swift
import UIKitimport Foundation
enum UILabelTextPositions : String {
case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"
}

使用UILabel扩展:

创建一个空的Swift类并命名它。添加以下内容

//  AppExtensions.swift
import Foundationimport 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)

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

Swift 2.2:

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

这解决了我的问题。

对于Swift 3…

@IBDesignable class TopAlignedLabel: UILabel {override func drawText(in rect: CGRect) {if let stringText = text {let stringTextAsNSString = stringText as NSStringlet labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width,height: CGFloat.greatestFiniteMagnitude),options: NSStringDrawingOptions.usesLineFragmentOrigin,attributes: [NSFontAttributeName: font],context: nil).sizesuper.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 = 1layer.borderColor = UIColor.black.cgColor}}

使用textRect(forBounds:limitedToNumberOfLines:)

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

使用Storyboard的最简单方法:

StackView中嵌入标签并在属性检查器中设置StackView的以下两个属性:

AxisHorizontal

2-AlignmentTop

在此处输入图片描述

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

在标签下方放置UIStackView

然后使用AutoLayout将标签的垂直行间距设置为零,并将顶部约束为以前标签的底部。标签不会增长,stackView会。我喜欢的是堆栈视图是非渲染的。所以它并没有真正浪费时间渲染。即使它进行了自动布局计算。

你可能需要玩ContentHu的和抵抗,但这也很简单。

我不时地谷歌这个问题并回到这里。这次我有一个我认为最简单的想法,我不认为它的性能不好。我必须说我只是在使用AutoLayout,不想麻烦计算帧。那只是…恶心。

以下是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 linesmyLabel.numberOfLines = 0myLabel.sizeToFit()
view.addSubview(myLabel) // add label}

(截至2018年3月7日)

Swift4

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.heightlet safeNewHeight = min(newFrameHeight, maxFrameHeight)
myLabel.frame = CGRect(x: 9, y: 9, width: 126, height: safeNewHeight)

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

我在我的应用程序中所做的是将UILabel的line属性设置为0,并创建UILabel的底部约束并确保它被设置为>=0,如下图所示。输入图片描述

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

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

SwiftUI

在SwiftUI中,所有视图通常都是尺寸大小它们的内容,但如果您显式使用frame修饰符,您可以使用框架的alignment参数:

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

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

ZStack(alignment: .top) {Color.redText("Text").background(Color.red)}

Swift5

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

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

你可以通过代码解决这个问题,或者简单地在故事板上执行以下操作:

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