如何为 iOS 应用程序设置 UILabel 的左上角对齐?

发布于 2024-12-01 07:17:09 字数 244 浏览 5 评论 0原文

我在 nib 文件中添加了一个标签,然后该标签需要左上对齐。由于我在运行时提供文本,因此不确定有多少行。 因此,如果文本仅包含单行,那么它会显示为垂直中心对齐。该对齐方式与我前面各自的标签不匹配。

例如:

在此处输入图像描述

这看起来很奇怪:(

有什么方法可以设置标签文本适合左上对齐吗?

I have added one label in my nib file, then its required to have top-left alignment for that lable. As I am providing text at runtime so its not sure that how much lines there are.
So if text contains only single line then it appears as vertical-center aligned. That alignment is not matching with my respective lable in front of it.

For example:

enter image description here

Which is looking odd :(

Is there any way where i can set label text proper to Top-Left alignment?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(26

梦一生花开无言 2024-12-08 07:17:10

Swift 5

这很简单,属性的顺序就是一切。

titleLabel.frame = CGRect(x: 20, y: 20, width: 374, height: 291.2)
titleLabel.backgroundColor = UIColor.clear //set a light color to see the frame
titleLabel.textAlignment = .left
titleLabel.lineBreakMode = .byTruncatingTail
titleLabel.numberOfLines = 4
titleLabel.font = UIFont(name: "HelveticaNeue-Bold", size: 35)
titleLabel.text = "Example"
titleLabel.sizeToFit()
self.view.addSubview(titleLabel)

Swift 5

It´s simple, the order of the properties is everything.

titleLabel.frame = CGRect(x: 20, y: 20, width: 374, height: 291.2)
titleLabel.backgroundColor = UIColor.clear //set a light color to see the frame
titleLabel.textAlignment = .left
titleLabel.lineBreakMode = .byTruncatingTail
titleLabel.numberOfLines = 4
titleLabel.font = UIFont(name: "HelveticaNeue-Bold", size: 35)
titleLabel.text = "Example"
titleLabel.sizeToFit()
self.view.addSubview(titleLabel)
一个人练习一个人 2024-12-08 07:17:10

我有这个问题,但我的标签在 UITableViewCell 中,并且解决该问题的最简单方法是创建一个空的 UIView 并在其中设置标签仅对顶部和左侧进行约束,关闭诅咒时将行数设置为 0

I have this problem to but my label was in UITableViewCell, and in fund that the easiest way to solve the problem was to create an empty UIView and set the label inside it with constraints to the top and to the left side only, on off curse set the number of lines to 0

半步萧音过轻尘 2024-12-08 07:17:10

我能够通过将标签嵌入视图中来修复它。效果很完美!

方式修复它:在视图中嵌入标签

I was able to fix it by embedding the tag within a view. It worked perfect!

Way of fix it: Embed the Label in a View

楠木可依 2024-12-08 07:17:10

您需要在layoutSubviews中设置:

override func layoutSubviews() {
   super.layoutSubviews()
   yourLabel.sizeToFit()
   //yourLabel.center.x = someView.center.x // optionally if exists
}

You need to set in layoutSubviews:

override func layoutSubviews() {
   super.layoutSubviews()
   yourLabel.sizeToFit()
   //yourLabel.center.x = someView.center.x // optionally if exists
}
落叶缤纷 2024-12-08 07:17:10

如何为 iOS 应用程序设置 UILabel 的左上角对齐?标签将内容模式设置为“左上”对我来说很有效,非常感谢:
如何为 iOS 应用程序设置 UILabel 的左上对齐?将标签内容模式设置为“左上”对我有用,非常感谢

How to set top-left alignment for UILabel for iOS application? Label Set Content Mode to "Top Left" work for me, thank you very much:
How to set top-left alignment for UILabel for iOS application? Label Set Content Mode to "Top Left" work for me, thank you very much

我很OK 2024-12-08 07:17:09

这很容易做到。使用 verticalAlignment 属性创建一个 UILabel 子类,并重写 textRectForBounds:limitedToNumberOfLines 以返回顶部、中间或底部垂直对齐的正确边界。代码如下:

SOLabel.h

#import <UIKit/UIKit.h>

typedef enum
{
    VerticalAlignmentTop = 0, // default
    VerticalAlignmentMiddle,
    VerticalAlignmentBottom,
} VerticalAlignment;

@interface SOLabel : UILabel

   @property (nonatomic, readwrite) VerticalAlignment verticalAlignment;

@end

SOLabel.m

@implementation SOLabel

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) return nil;

    // set inital value via IVAR so the setter isn't called
    _verticalAlignment = VerticalAlignmentTop;

    return self;
}

-(VerticalAlignment) verticalAlignment
{
    return _verticalAlignment;
}

-(void) setVerticalAlignment:(VerticalAlignment)value
{
    _verticalAlignment = value;
    [self setNeedsDisplay];
}

// align text block according to vertical alignment settings
-(CGRect)textRectForBounds:(CGRect)bounds 
    limitedToNumberOfLines:(NSInteger)numberOfLines
{
   CGRect rect = [super textRectForBounds:bounds 
                   limitedToNumberOfLines:numberOfLines];
    CGRect result;
    switch (_verticalAlignment)
    {
       case VerticalAlignmentTop:
          result = CGRectMake(bounds.origin.x, bounds.origin.y, 
                              rect.size.width, rect.size.height);
           break;

       case VerticalAlignmentMiddle:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
                    rect.size.width, rect.size.height);
          break;

       case VerticalAlignmentBottom:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height),
                    rect.size.width, rect.size.height);
          break;

       default:
          result = bounds;
          break;
    }
    return result;
}

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

@end

It's fairly easy to do. Create a UILabel sublcass with a verticalAlignment property and override textRectForBounds:limitedToNumberOfLines to return the correct bounds for a top, middle or bottom vertical alignment. Here's the code:

SOLabel.h

#import <UIKit/UIKit.h>

typedef enum
{
    VerticalAlignmentTop = 0, // default
    VerticalAlignmentMiddle,
    VerticalAlignmentBottom,
} VerticalAlignment;

@interface SOLabel : UILabel

   @property (nonatomic, readwrite) VerticalAlignment verticalAlignment;

@end

SOLabel.m

@implementation SOLabel

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) return nil;

    // set inital value via IVAR so the setter isn't called
    _verticalAlignment = VerticalAlignmentTop;

    return self;
}

-(VerticalAlignment) verticalAlignment
{
    return _verticalAlignment;
}

-(void) setVerticalAlignment:(VerticalAlignment)value
{
    _verticalAlignment = value;
    [self setNeedsDisplay];
}

// align text block according to vertical alignment settings
-(CGRect)textRectForBounds:(CGRect)bounds 
    limitedToNumberOfLines:(NSInteger)numberOfLines
{
   CGRect rect = [super textRectForBounds:bounds 
                   limitedToNumberOfLines:numberOfLines];
    CGRect result;
    switch (_verticalAlignment)
    {
       case VerticalAlignmentTop:
          result = CGRectMake(bounds.origin.x, bounds.origin.y, 
                              rect.size.width, rect.size.height);
           break;

       case VerticalAlignmentMiddle:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
                    rect.size.width, rect.size.height);
          break;

       case VerticalAlignmentBottom:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height),
                    rect.size.width, rect.size.height);
          break;

       default:
          result = bounds;
          break;
    }
    return result;
}

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

@end
对风讲故事 2024-12-08 07:17:09

我将链接到这个相当广泛的内容,而不是重新解释。评价很高的问题/答案:

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

简短的答案是否定的,Apple 没有这并不容易,但可以通过更改框架大小来实现。

Rather than re-explaining, I will link to this rather extensive & highly rated question/answer:

Vertically align text to top within a UILabel

The short answer is no, Apple didn't make this easy, but it is possible by changing the frame size.

反话 2024-12-08 07:17:09

我在 StoryBoard 中找到了使用 AutoLayout 的解决方案。

1) 将行数设置为 0,并将文本对齐方式设置为左。

在此处输入图片描述

2) 设置高度约束。

在此处输入图像描述

3) 高度约束应为关系 - 小于或等于

在此处输入图像描述

4)

   override func viewWillLayoutSubviews() {
        sampleLabel.sizeToFit()
    }

我得到的结果如下:

在此处输入图像描述

I found a solution using AutoLayout in StoryBoard.

1) Set no of lines to 0 and text alignment to Left.

enter image description here

2) Set height constraint.

enter image description here

3) The height Constraint should be in Relation - Less Than or Equal

enter image description here

4)

   override func viewWillLayoutSubviews() {
        sampleLabel.sizeToFit()
    }

I got the result as follows :

enter image description here

巷雨优美回忆 2024-12-08 07:17:09

SOLabel 对我有用。

斯威夫特 3 & 5:

该版本已从原始版本更新为允许支持 RTL 语言:

public class VerticalAlignLabel: UILabel {
    enum VerticalAlignment {
        case top
        case middle
        case bottom
    }

    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }

    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
            switch verticalAlignment {
            case .top:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        } else {
            switch verticalAlignment {
            case .top:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        }
    }

    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

Swift 1:

class UIVerticalAlignLabel: UILabel {

enum VerticalAlignment : Int {
    case VerticalAlignmentTop = 0
    case VerticalAlignmentMiddle = 1
    case VerticalAlignmentBottom = 2
}

var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
    didSet {
        setNeedsDisplay()
    }
}

required init(coder aDecoder: NSCoder){
    super.init(coder: aDecoder)
}

override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
    let rect = super.textRectForBounds(bounds, limitedToNumberOfLines: limitedToNumberOfLines)

    switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height)
        default:
            return bounds
    }
}

override func drawTextInRect(rect: CGRect) {
    let r = self.textRectForBounds(rect, limitedToNumberOfLines: self.numberOfLines)
    super.drawTextInRect(r)
    }
}

The SOLabel works for me.

Swift 3 & 5:

This version has been updated from the original to allow support for RTL languages:

public class VerticalAlignLabel: UILabel {
    enum VerticalAlignment {
        case top
        case middle
        case bottom
    }

    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }

    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
            switch verticalAlignment {
            case .top:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        } else {
            switch verticalAlignment {
            case .top:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        }
    }

    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

Swift 1:

class UIVerticalAlignLabel: UILabel {

enum VerticalAlignment : Int {
    case VerticalAlignmentTop = 0
    case VerticalAlignmentMiddle = 1
    case VerticalAlignmentBottom = 2
}

var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
    didSet {
        setNeedsDisplay()
    }
}

required init(coder aDecoder: NSCoder){
    super.init(coder: aDecoder)
}

override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
    let rect = super.textRectForBounds(bounds, limitedToNumberOfLines: limitedToNumberOfLines)

    switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height)
        default:
            return bounds
    }
}

override func drawTextInRect(rect: CGRect) {
    let r = self.textRectForBounds(rect, limitedToNumberOfLines: self.numberOfLines)
    super.drawTextInRect(r)
    }
}
柒夜笙歌凉 2024-12-08 07:17:09

就我而言,这是底部空间约束问题。我已将其设置为 = 16

当我将其设置为 bottom to >= 16 时,这个问题得到了解决。

另外,如果标签中有任何高度限制,则需要将其删除。

这是尺寸检查器中我的标签的约束视图:

constraint

In my case, it was bottom space constraint issue. I had set it to = 16.

When I set it to bottom to >= 16, this issue got solved.

Also, if you have any height constraint in the label, then you need to remove it.

Here's my label's constraint view in the size inspector:

constraint

别念他 2024-12-08 07:17:09

在代码中

label.text = @"some text";
[label sizeToFit];

请注意,如果您在表格单元格或其他使用不同数据回收的视图中使用它,则需要将原始框架存储在某处并在调用 sizeToFit 之前重置它。

In your code

label.text = @"some text";
[label sizeToFit];

Beware that if you use that in table cells or other views that get recycled with different data, you'll need to store the original frame somewhere and reset it before calling sizeToFit.

记忆消瘦 2024-12-08 07:17:09

我找到了同一问题的另一个解决方案。我使用 UITextView 而不是 UILabel 并将 editable() 函数切换为 false

I found another solution for the same problem. I used UITextView instead of UILabel and switched editable() function to false.

紫南 2024-12-08 07:17:09

我也遇到了这个问题,但我发现设置 UILabel 的属性和方法的顺序很重要!

如果您在 label.font = [UIFont fontWithName:@"Helvetica" size:14]; 之前调用 [label sizeToFit] ,则文本不会与顶部对齐,但如果你交换它们然后就可以了!

我还注意到,首先设置文本也会产生影响。

希望这有帮助。

I was also having this problem but what I found was the the order in which you set the UILabel's properties and methods matters!

If you call [label sizeToFit] before label.font = [UIFont fontWithName:@"Helvetica" size:14]; then the text does not align to the top but if you swap them around then it does!

I also noticed that setting the text first makes a difference too.

Hope this helps.

习ぎ惯性依靠 2024-12-08 07:17:09

当您使用界面生成器时,请设置标签的约束(请务必设置高度和宽度)。然后在尺寸检查器中,检查标签的高度。在那里,您将希望它读取 >= 而不是 =。然后在该视图控制器的实现中,将行数设置为 0(也可以在 IB 中完成)并设置标签 [label sizeToFit];随着文本长度的增加,标签的高度也会增加,并使文本保持在左上角。

As you are using the interface builder, set the constraints for your label (be sure to set the height and width as well). Then in the Size Inspector, check the height for the label. There you will want it to read >= instead of =. Then in the implementation for that view controller, set the number of lines to 0 (can also be done in IB) and set the label [label sizeToFit]; and as your text gains length, the label will grow in height and keep your text in the upper left.

清音悠歌 2024-12-08 07:17:09

如果您需要的是默认从左上角开始的不可编辑文本,您可以简单地使用文本视图而不是标签,然后将其状态设置为不可编辑,如下所示:

textview.isEditable = false

比弄乱标签更容易。 ..

干杯!

If what you need is non-editable text that by default starts at the top left corner you can simply use a Text View instead of a label and then set its state to non-editable, like this:

textview.isEditable = false

Way easier than messing with the labels...

Cheers!

ま柒月 2024-12-08 07:17:09

SoLabel 的解决方案有效,谢谢。

下面我添加了单点触控版本:

    public class UICustomLabel : UILabel
{
    private UITextVerticalAlignment _textVerticalAlignment;

    public UICustomLabel()
    {
        TextVerticalAlignment = UITextVerticalAlignment.Top;
    }

    public UITextVerticalAlignment TextVerticalAlignment
    {
        get
        {
            return _textVerticalAlignment;
        }
        set
        {
            _textVerticalAlignment = value;
            SetNeedsDisplay();
        }
    }

    public override void DrawText(RectangleF rect)
    {
        var bound = TextRectForBounds(rect, Lines);
        base.DrawText(bound);
    }

    public override RectangleF TextRectForBounds(RectangleF bounds, int numberOfLines)
    {
        var rect = base.TextRectForBounds(bounds, numberOfLines);
        RectangleF resultRect;
        switch (TextVerticalAlignment)
        {
            case UITextVerticalAlignment.Top:
                resultRect = new RectangleF(bounds.X, bounds.Y, rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Middle:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height)/2,
                                            rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Bottom:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height),
                                            rect.Size.Width, rect.Size.Height);
                break;

            default:
                resultRect = bounds;
                break;
        }

        return resultRect;
    }
}

public enum UITextVerticalAlignment
{
    Top = 0, // default
    Middle,
    Bottom
}

Solution with SoLabel works , Thanks.

Bellow I have added monotouch version:

    public class UICustomLabel : UILabel
{
    private UITextVerticalAlignment _textVerticalAlignment;

    public UICustomLabel()
    {
        TextVerticalAlignment = UITextVerticalAlignment.Top;
    }

    public UITextVerticalAlignment TextVerticalAlignment
    {
        get
        {
            return _textVerticalAlignment;
        }
        set
        {
            _textVerticalAlignment = value;
            SetNeedsDisplay();
        }
    }

    public override void DrawText(RectangleF rect)
    {
        var bound = TextRectForBounds(rect, Lines);
        base.DrawText(bound);
    }

    public override RectangleF TextRectForBounds(RectangleF bounds, int numberOfLines)
    {
        var rect = base.TextRectForBounds(bounds, numberOfLines);
        RectangleF resultRect;
        switch (TextVerticalAlignment)
        {
            case UITextVerticalAlignment.Top:
                resultRect = new RectangleF(bounds.X, bounds.Y, rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Middle:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height)/2,
                                            rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Bottom:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height),
                                            rect.Size.Width, rect.Size.Height);
                break;

            default:
                resultRect = bounds;
                break;
        }

        return resultRect;
    }
}

public enum UITextVerticalAlignment
{
    Top = 0, // default
    Middle,
    Bottom
}
耀眼的星火 2024-12-08 07:17:09

最简单、最简单的方法是在 StackView 中嵌入 Label 并将 StackView 的轴设置为水平,在 Storyboard 的属性检查器中将对齐方式设置为顶部 如下所示< /a>.

The simplest and easiest way is to embed Label in StackView and setting StackView's Axis to Horizontal, Alignment to Top in Attribute Inspector from Storyboard like shown here.

Smile简单爱 2024-12-08 07:17:09

使用UITextView而不是UILabel。它还适用于 UITableViewCell 宽度自动行高

isScrollEnabledisEditable 设置为 false。为 TextView 添加最小高度限制

单行文本截图

多行文字截图

final class TestVC: UIViewController {
    
    lazy var testTextLabel: UITextView = {
        $0.isScrollEnabled = false
        $0.isEditable = false
        
        $0.font = .systemFont(ofSize: 17, weight: .medium)
        $0.textColor = .black
        
        $0.layer.borderWidth = 1
        $0.layer.borderColor = UIColor.black.cgColor
        $0.layer.cornerRadius = 5
        
        return $0
    }(UITextView())
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        testTextLabel.text = "Your text"
        
        view.addSubview(testTextLabel)
        testTextLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            testTextLabel.topAnchor.constraint(equalTo: testTextLabel.superview!.safeAreaLayoutGuide.topAnchor, constant: 12),
            testTextLabel.leadingAnchor.constraint(equalTo: testTextLabel.superview!.leadingAnchor, constant:  12),
            testTextLabel.widthAnchor.constraint(equalToConstant: 250),
            testTextLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 70)
        ])
    }
}

Use UITextView instead of UILabel. Also it works for UITableViewCell width automatic row height

Set isScrollEnabled and isEditable to false. Add min height constraint for TextView

One line text screenshot

Multiline text screenshot

final class TestVC: UIViewController {
    
    lazy var testTextLabel: UITextView = {
        $0.isScrollEnabled = false
        $0.isEditable = false
        
        $0.font = .systemFont(ofSize: 17, weight: .medium)
        $0.textColor = .black
        
        $0.layer.borderWidth = 1
        $0.layer.borderColor = UIColor.black.cgColor
        $0.layer.cornerRadius = 5
        
        return $0
    }(UITextView())
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        testTextLabel.text = "Your text"
        
        view.addSubview(testTextLabel)
        testTextLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            testTextLabel.topAnchor.constraint(equalTo: testTextLabel.superview!.safeAreaLayoutGuide.topAnchor, constant: 12),
            testTextLabel.leadingAnchor.constraint(equalTo: testTextLabel.superview!.leadingAnchor, constant:  12),
            testTextLabel.widthAnchor.constraint(equalToConstant: 250),
            testTextLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 70)
        ])
    }
}
半寸时光 2024-12-08 07:17:09

在 totiG 的出色答案的基础上,我创建了一个 IBDesignable 类,可以非常轻松地从 StoryBoard 自定义 UILabel 的垂直对齐方式。只需确保从 StoryBoard 身份检查器将 UILabel 的类设置为“VerticalAlignLabel”即可。如果垂直对齐没有生效,请转到编辑器->刷新所有视图,这应该可以解决问题。

工作原理:
正确设置 UILabel 的类后,故事板应该向您显示一个采用整数(对齐代码)的输入字段。

更新:我添加了对居中标签的支持 ~Sev


输入 0 表示顶部对齐

输入 1 表示中间对齐

输入 2 表示底部对齐

    @IBDesignable class VerticalAlignLabel: UILabel {
    
    @IBInspectable var alignmentCode: Int = 0 {
        didSet {
            applyAlignmentCode()
        }
    }
    
    func applyAlignmentCode() {
        switch alignmentCode {
        case 0:
            verticalAlignment = .top
        case 1:
            verticalAlignment = .topcenter
        case 2:
            verticalAlignment = .middle
        case 3:
            verticalAlignment = .bottom
        default:
            break
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.applyAlignmentCode()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        
        self.applyAlignmentCode()
    }
    
    enum VerticalAlignment {
        case top
        case topcenter
        case middle
        case bottom
    }
    
    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }
    
    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
        
        if #available(iOS 9.0, *) {
            if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            } else {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            }
        } else {
            // Fallback on earlier versions
            return rect
        }
    }
    
    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

Building on top of totiG's awesome answer, I have created an IBDesignable class that makes it extremely easy to customize a UILabel's vertical alignment right from the StoryBoard. Just make sure that you set your UILabel's class to 'VerticalAlignLabel' from the StoryBoard identity inspector. If the vertical alignment doesn't take effect, go to Editor->Refresh All Views which should do the trick.

How it works:
Once you set your UILabel's class correctly, the storyboard should show you an input field that takes an integer (alignment code).

Update: I've added support for centered labels ~Sev


Enter 0 for Top Alignment

Enter 1 for Middle Alignment

Enter 2 for Bottom Alignment

    @IBDesignable class VerticalAlignLabel: UILabel {
    
    @IBInspectable var alignmentCode: Int = 0 {
        didSet {
            applyAlignmentCode()
        }
    }
    
    func applyAlignmentCode() {
        switch alignmentCode {
        case 0:
            verticalAlignment = .top
        case 1:
            verticalAlignment = .topcenter
        case 2:
            verticalAlignment = .middle
        case 3:
            verticalAlignment = .bottom
        default:
            break
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.applyAlignmentCode()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        
        self.applyAlignmentCode()
    }
    
    enum VerticalAlignment {
        case top
        case topcenter
        case middle
        case bottom
    }
    
    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }
    
    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
        
        if #available(iOS 9.0, *) {
            if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            } else {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            }
        } else {
            // Fallback on earlier versions
            return rect
        }
    }
    
    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

终难愈 2024-12-08 07:17:09

只需覆盖 drawText 并使用 textRect(forBounds:limitedToNumberOfLines:)

所以:

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

Simply override drawText and use textRect(forBounds:limitedToNumberOfLines:)

So:

class TopAlignedLabel: UILabel {
      override func drawText(in rect: CGRect) {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        super.drawText(in: textRect)
      }
}
匿名。 2024-12-08 07:17:09

@totiG 答案的 Swift 3 版本

class UIVerticalAlignLabel: UILabel {
    enum VerticalAlignment : Int {
        case VerticalAlignmentTop = 0
        case VerticalAlignmentMiddle = 1
        case VerticalAlignmentBottom = 2
    }

    @IBInspectable var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
        didSet {
            setNeedsDisplay()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
        }
    }

    override func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

Swift 3 version of @totiG's answer

class UIVerticalAlignLabel: UILabel {
    enum VerticalAlignment : Int {
        case VerticalAlignmentTop = 0
        case VerticalAlignmentMiddle = 1
        case VerticalAlignmentBottom = 2
    }

    @IBInspectable var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
        didSet {
            setNeedsDisplay()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
        }
    }

    override func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}
伪心 2024-12-08 07:17:09

您也可以将 UILabel 更改为 UITextView,因为它们基本上做相同的事情,除了 UITextView 的优点是文本自动对齐到左上角

you can also just change your UILabel to UITextView, because they basically do the same thing except the advantage of UITextView is that text is automatically aligned to the top left

娇柔作态 2024-12-08 07:17:09

@totiG 的答案是正确的并解决了我的问题。但我在实现这个方法时发现了一个问题,在像5s、SE这样的较小设备上,这对我来说不起作用。我必须在 override func layoutSubViews() 中设置 label.sizeToFit()

override func layoutSubViews() {
    super.layoutSubViews()
    // Do other works if needed
    label.sizeToFit()
}

@totiG's answer is correct and solved my problem. But I found a problem while implementing this method, in smaller devices like 5s , SE, this doesn't work for me. I have to set label.sizeToFit() in override func layoutSubViews()

override func layoutSubViews() {
    super.layoutSubViews()
    // Do other works if needed
    label.sizeToFit()
}
我的黑色迷你裙 2024-12-08 07:17:09

纯故事板解决方案...

水平左对齐很容易,因为它可以在 Interface Builder 中设置为 UILabel 属性。

垂直顶部对齐只需两个约束即可设置:

  1. 一个将 UILabel.bottom 设置为大于或等于某个其他视图(最大高度),优先级为 1000(必需)。这将增加 UILabel 增长到该约束高度的能力

  2. 其他设置 UILabel.bottom 为 equal 0(最小高度),优先级为 750(非必需)。这将增加 UILabel 缩小到其内容允许的最小尺寸的能力/趋势

这意味着 UIKit 将尝试根据其属性/内容(文本、字体、. ..) 最大为 1. 约束高度。

Pure Storyboard solution...

Horizontal left alignment is easy since it can be setup as UILabel property in Interface Builder.

Vertical top alignment can be setup with just two constraints:

  1. one that setups UILabel.bottom as greater or equal to some other view (maximal height) with priority like 1000 (required). This will add UILabel ability to grow up to this constraint's height

  2. other that setups UILabel.bottom like equal 0 (minimal height) with priority like 750 (non-required). This will add UILabel ability/tendency to shrink to minimal size allowed by its content

This means that UIKit will try to setup UILabel height as minimal as possible in range from minimal auto-sized UILabel based on its properties/content (text, font, ...) up to 1. constraint height.

梦里°也失望 2024-12-08 07:17:09

对于 iOS 7,这就是我所做的并为我工作

@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                              attributes:attributes
                                                 context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    CGRect newFrame = self.frame;
    newFrame.size.height = numberOfLines * self.font.lineHeight;
    self.frame = newFrame;
}

- (void)alignBottom
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                            attributes:attributes
                                               context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    int numberOfNewLined = (self.frame.size.height/self.font.lineHeight) - numberOfLines;

    NSMutableString *newLines = [NSMutableString string];
    for(int i=0; i< numberOfNewLined; i++){
        [newLines appendString:@"\n"];
    }
    [newLines appendString:self.text];
    self.text = [newLines mutableCopy];
}

For iOS 7 that's what i made and worked for me

@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                              attributes:attributes
                                                 context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    CGRect newFrame = self.frame;
    newFrame.size.height = numberOfLines * self.font.lineHeight;
    self.frame = newFrame;
}

- (void)alignBottom
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                            attributes:attributes
                                               context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    int numberOfNewLined = (self.frame.size.height/self.font.lineHeight) - numberOfLines;

    NSMutableString *newLines = [NSMutableString string];
    for(int i=0; i< numberOfNewLined; i++){
        [newLines appendString:@"\n"];
    }
    [newLines appendString:self.text];
    self.text = [newLines mutableCopy];
}
滥情哥ㄟ 2024-12-08 07:17:09

Swift 2.0::使用 UILabel 扩展

在空 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)

Swift 2.0: : Using UILabel Extension

Make constant enum values in a empty Swift file.

//  AppRef.swift

import UIKit
import Foundation

enum UILabelTextPositions : String {

 case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
 case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
 case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"

}

Using UILabel Extension:

Make a empty Swift class and name it. Add the following.

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

     }
    }

Usage :

myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文