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

Ste*_*fan 2141 xcode cocoa-touch text-alignment uikit ios

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

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

表示具有垂直居中文本的UILabel的图像

nev*_*ing 2676

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

这是快速简便的方法:

    [myLabel sizeToFit];
Run Code Online (Sandbox Code Playgroud)

sizeToFit来挤压标签


如果您的文本较长的标签将生成多行,则设置numberOfLines0(此处为零表示无限数量的行).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];
Run Code Online (Sandbox Code Playgroud)

使用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];
}
Run Code Online (Sandbox Code Playgroud)

使用的一些限制sizeToFit与中心或右对齐文本相关.这是发生的事情:

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

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

标签的大小仍然是固定的左上角.您可以将原始标签的宽度保存在变量中并在之后设置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;
Run Code Online (Sandbox Code Playgroud)

标签对齐


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

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

其他一些注意事项:

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


Mark Amery在评论中使用自动布局修复了NIB和故事板:

如果您的标签作为view使用自动布局的ViewController 的子视图包含在笔尖或故事板中,那么将您的sizeToFit调用放入其中viewDidLoad将无效,因为调用后自动布局大小和位置后的子视图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;
Run Code Online (Sandbox Code Playgroud)

  • 你需要删除autolayout (10认同)
  • 这是解决问题的简单方法:http://stackoverflow.com/a/26632490/636559 (4认同)
  • 这个答案是不必要的复杂,它使用"周围的字".请参阅下面的建议,只需更改垂直内容拥抱优先级.不需要任何代码...... (3认同)
  • 您仍然可以使用自动布局和约束,但请确保[高度]不会被固定。例如:将Left、Top、Right设置为等于8px,但Bottom可以设置“大于或等于”8px。它会对 iOS 说,让我的 sizeToFit 决定标签的更好高度。 (2认同)

Jak*_*ger 334

  1. 设置新文本:

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

    myLabel.numberOfLines = 0
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将标签的框架设置为最大尺寸:

    myLabel.frame = CGRectMake(20,20,200,800)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 调用sizeToFit以减小帧大小,使内容适合:

    [myLabel sizeToFit]
    
    Run Code Online (Sandbox Code Playgroud)

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

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


Dmi*_*nko 158

参考扩展解决方案:

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

应该被替换

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

每个添加的换行符都需要额外的空间,因为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
Run Code Online (Sandbox Code Playgroud)

然后调用[yourLabel alignTop];[yourLabel alignBottom];在每个yourLabel文本分配后.


jow*_*wie 143

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

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

在此输入图像描述

  • 此线程中的所有其他解决方案在iOS 7中无效(无论出于何种原因).但只需使用"UITextView"即可立即给我提供所需的结果. (2认同)
  • 此方法的一个小缺点是它会给文本引入额外的固有填充。一个快速解决方法是引入负面约束。 (2认同)

jas*_*ori 112

没有麻烦,没有大惊小怪

@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
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

  • 可能是这里最好的答案,适用于所有场景。如果标签在 UITableviewCell 中,则 sizeToFit 不起作用。干得好。 (7认同)

Bad*_*ate 77

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

然后使用,将您的文本放入标签,然后调用适当的方法来对齐它:

[myLabel alignTop];
Run Code Online (Sandbox Code Playgroud)

要么

[myLabel alignBottom];
Run Code Online (Sandbox Code Playgroud)


Pur*_*irl 69

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

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];
Run Code Online (Sandbox Code Playgroud)

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

  • 将换行模式设置为'clip'似乎搞乱了标签的自动调整大小.请改用"UILineBreakModeWordWrap". (3认同)

iva*_*oid 61

而不是UILabel你可以使用UITextField哪个有垂直对齐选项:

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction
Run Code Online (Sandbox Code Playgroud)

  • 警告:UITextField只允许单行文本. (7认同)
  • 要完成@DavidJames评论:UITextView会更合适 (2认同)

Bai*_*aig 53

故事板解决方案: 最简单和最简单的方法是嵌入AxisHorizontal和设置StackView的AlignmentTop,AxisHorizontalAlignment从故事板.

在此输入图像描述

  • 为了获得更好的结果,您可以执行此操作 StackView &gt; View &gt; UILabel,因为当您将 UILabel 嵌入 StackView 时,StackView 会调整大小以适合 UILabel 的最小尺寸 (2认同)

Dav*_*eco 50

我很长时间都在努力解决这个问题,我想分享我的解决方案.

这将为您提供一个UILabel自动收缩文本,缩小到0.5刻度,并垂直居中文本.Storyboard/IB中也提供了这些选项.

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
Run Code Online (Sandbox Code Playgroud)


seb*_*ich 44

创建一个新类

LabelTopAlign

.h文件

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)

编辑

这是一个更简单的实现,它做了同样的事情:

#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
Run Code Online (Sandbox Code Playgroud)


bea*_*ain 38

在此输入图像描述

在Interface Builder中

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

在你的代码中

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

代码片段:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];
Run Code Online (Sandbox Code Playgroud)


Rab*_*ndi 34

对于自适应UI(iOS8或之后),UILabel的垂直对齐将通过更改属性noOfLines= 0`从StoryBoard设置.

约束

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

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

UILabel的制约因素

编辑:

noOfLines=0
Run Code Online (Sandbox Code Playgroud)

并且以下约束足以实现期望的结果.

在此输入图像描述


Mar*_*man 33

创建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
Run Code Online (Sandbox Code Playgroud)

作为讨论在这里.


fir*_*oke 27

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


Wal*_*ung 26

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

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

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


小智 19

我在这里提出了建议并创建了一个视图,它可以包装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
Run Code Online (Sandbox Code Playgroud)


And*_*nov 18

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

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

//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;
Run Code Online (Sandbox Code Playgroud)


Cod*_*die 15

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

myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];
Run Code Online (Sandbox Code Playgroud)

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

因为有时候足够好就足够了.

  • @CodeRoadie快速和肮脏为我做了伎俩,我有一些布局问题与真正的答案.我可以用"正确的方式"做到这一点,但谢谢你为我节省了一些时间! (2认同)

pet*_*are 15

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

自动布局使这个问题变得微不足道.假设我们要添加标签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}]];
Run Code Online (Sandbox Code Playgroud)

标签的高度将自动计算(使用它intrinsicContentSize),标签将水平放置在边缘到边缘,位于顶部view.


小智 15

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


Joh*_*nus 14

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

- (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];
}
Run Code Online (Sandbox Code Playgroud)

然后当我想改变我的标签文本时......

- (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];
}
Run Code Online (Sandbox Code Playgroud)

希望有人帮助!


jjx*_*tra 14

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


Nir*_*gas 11

对于阅读此内容的任何人,因为标签内的文字不是垂直居中的,请记住某些字体类型的设计不同.例如,如果您创建zapfino大小为16的标签,您将看到文本没有完全垂直居中.

但是,使用helvetica会使文本垂直居中.


jrc*_*jrc 10

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

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

    [super drawTextInRect:rect];
}
Run Code Online (Sandbox Code Playgroud)

我尝试了涉及换行填充的解决方案,并在某些情况下遇到了错误的行为.根据我的经验,如上所述限制绘图矩形比混乱更容易numberOfLines.

PS你可以想象通过这种方式轻松支持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];
}
Run Code Online (Sandbox Code Playgroud)


pha*_*ann 10

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


ma1*_*w28 10

使用textRect(forBounds:limitedToNumberOfLines:).

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

  • 这个答案应该得到_way_更多的赞成,因为它是迄今为止最好和最干净的解决方案! (3认同)
  • 先生您真是神啊! (2认同)
  • 非常优雅的解决方案 (2认同)

dim*_*iax 9

雨燕5

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

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


the*_*ign 8

只要您没有执行任何复杂的任务,您就可以使用UITextView而不是UILabels.

禁用滚动.

如果您希望文本完全显示只是用户sizeToFitsizeThatFits:方法


小智 8

在迅速,

let myLabel : UILabel!

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

myLabel.sizeToFit()

使标签的字体适合屏幕宽度或特定宽度尺寸.

myLabel.adjustsFontSizeToFitWidth = YES

和一些标签的textAlignment:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified


Sul*_*han 7

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

我的解决方案:
1 /我自己分割线(忽略标签包装设置)
2 /自己画线(忽略标签对齐)


@interface UITopAlignedLabel : UILabel

@end
Run Code Online (Sandbox Code Playgroud)

@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
Run Code Online (Sandbox Code Playgroud)


小智 6

如果创建自己的自定义视图是一个选项,您可以执行以下操作:

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


小智 6

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

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


bar*_*dog 6

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

在我看来,使用drawRect有点贵.使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_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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


A.G*_*A.G 6

Swift 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"

}
Run Code Online (Sandbox Code Playgroud)

使用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!

 }
}
Run Code Online (Sandbox Code Playgroud)

用法:

myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)
Run Code Online (Sandbox Code Playgroud)


sea*_*ard 5

我对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)); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


vbw*_*bwx 5

我也在研究这个特定的问题,所以我采用了DSnevan king的想法,基本上将它们组合成一个实现垂直对齐属性的子类,这也允许你更改对齐而不仅仅是一次.它借用了UIControlContentVerticalAlignment类型并且也支持UIControlContentVerticalAlignmentFill.

从我所看到的,numberOfLines在垂直对齐方面似乎毫无用处,因此在应用垂直对齐时,在此子类中始终将其设置为0.此外,您还需要自行设置lineBreakMode以防万一您需要多行文本标签.

它是:GALHub上的QALabel


seg*_*ggy 5

对于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
    }
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*erd 5

(截至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)
Run Code Online (Sandbox Code Playgroud)

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