垂直对齐 UILabel 中的文本(注意:使用 AutoLayout)

问题描述 投票:0回答:17

我正在复制之前问过的相同问题Question。 我已经尝试了给出的解决方案但无法解决它,因为 sizetofit 在我使用 Autolayout 时无效。

first screenshot

预期的显示如下。

second screenshot

ios objective-c cocoa-touch autolayout uilabel
17个回答
135
投票

编辑

在我最初的回答中,我使用的是标签的段落样式。事实证明,对于多行标签,这实际上可以防止标签成为多行。结果我把它从计算中删除了。在Github

中查看更多相关信息

对于那些更习惯使用开源的人,请务必查看TTTAtributedLabel,您可以在其中将标签的文本对齐方式设置为

TTTAttributedLabelVerticalAlignmentTop


诀窍是继承

UILabel
并覆盖
drawTextInRect
。然后强制在标签边界的原点绘制文本。

这是您现在可以使用的简单实现:

斯威夫特

@IBDesignable class TopAlignedLabel: UILabel {
    override func drawTextInRect(rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            var labelStringSize = stringTextAsNSString.boundingRectWithSize(CGSizeMake(CGRectGetWidth(self.frame), CGFloat.max),
                options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                attributes: [NSFontAttributeName: font],
                context: nil).size
            super.drawTextInRect(CGRectMake(0, 0, CGRectGetWidth(self.frame), ceil(labelStringSize.height)))
        } else {
            super.drawTextInRect(rect)
        }
    }
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.blackColor().CGColor
    }
}

斯威夫特 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
    }
}

目标-C

IB_DESIGNABLE
@interface TopAlignedLabel : UILabel

@end

@implementation TopAlignedLabel

- (void)drawTextInRect:(CGRect)rect {
    if (self.text) {
        CGSize labelStringSize = [self.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.frame), CGFLOAT_MAX)
                                                         options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                                      attributes:@{NSFontAttributeName:self.font}
                                                         context:nil].size;
        [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),ceilf(labelStringSize.height))];
    } else {
        [super drawTextInRect:rect];
    }
}

- (void)prepareForInterfaceBuilder {
        [super prepareForInterfaceBuilder];
        self.layer.borderWidth = 1;
        self.layer.borderColor = [UIColor blackColor].CGColor;
}

@end

因为我使用了 IBDesignable,所以您可以将这个标签添加到故事板中并观察它的运行,这就是我的样子

enter image description here


47
投票

如果您不受固定大小的 UILabel 的限制,而不是在 UILabel 中对齐文本,只需在给定标签上使用 ≥ 约束来更改它的大小。

这是使用自动布局的最优雅的解决方案。不要忘记将numberOfLines设置为零。


33
投票

您可以使用 UITextView 而不是 UILabel:
取消选中“启用滚动”
取消选中“可编辑”
取消选中“可选”
将背景颜色设置为 ClearColor


8
投票

我遇到了同样的问题,我就是这样解决的。我刚刚在标签的属性检查器下编辑了基线。将其设置为“对齐中心”。


7
投票

相反,我将 Bottom Space Constant 更改为优先级 @250 并解决了我的问题。我的标签的高度与 <= constant

保持一致

4
投票

您可以通过删除最小高度来做到这一点。

如果您需要标签下方其他内容的最小高度,那么您将使用根据标签内容调整大小但使用最小值的容器视图。


2
投票

对于标签高度不需要恒定的情况,有一个简单的解决方案:将您的

Label
放在
Stack View
中。请务必将前导和尾随常量添加到
Stack View
。这是如何在情节提要中执行此操作的屏幕截图:


1
投票

自动布局仅适用于控制器的边缘/尺寸,不适用于控制器内容。因此使用自动布局在第一行顶部显示标签文本不是一个好主意。 根据我的说法,sizetofit 是这样做的最佳选择。


1
投票

我使用了@Daniel Golasko 的解决方案,只要 UILabel 中的文本长于 UILabel 可以包含的内容,文本就会开始向下移动,而不是保持与顶部对齐。

我更改了这一行以确保文本正确对齐

    [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),MIN(ceilf(labelStringSize.height), self.frame.size.height))];

1
投票

我有一个类似的问题,有 3 个标签。中间的标签可以有比其他两个标签更长的文本,因此它的高度可以变得更大。

像这样:

我将中间标签的底部空间约束设置为 >= 底部标签。

这解决了我的问题。


1
投票

这里是 Daniel Galasko 对 Swift 3 解决方案的改进(这里你还可以设置最大行号,而不在顶部偏移):

import UIKit

@IBDesignable class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelString = stringTextAsNSString.boundingRect(with: CGSize(width: frame.width, height: .greatestFiniteMagnitude),
                    options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
            super.drawText(in: CGRect(x: 0, y: 0, width: frame.width, height: ceil(labelString.size.height) > frame.height ? frame.height : ceil(labelString.size.height)))
        } else {
            super.drawText(in: rect)
        }
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.black.cgColor
    }
}

1
投票

斯威夫特 4

你应该继承 UILabel 并覆盖文本显示渲染。

class UITopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        guard let string = text else {
            super.drawText(in: rect)
            return
        }

        let size = (string as NSString).boundingRect(
            with: CGSize(width: rect.width, height: .greatestFiniteMagnitude),
            options: [.usesLineFragmentOrigin],
            attributes: [.font: font],
            context: nil).size

        var rect = rect
        rect.size.height = size.height.rounded()
        super.drawText(in: rect)
    }
}

0
投票

你可以试试如果按钮

[button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];

编辑:

如果你只想使用标签,你可以试试这个:

https://stackoverflow.com/a/11278660/1223897


0
投票

对于我来说,我没有设置高度限制,文本总是从标签的顶部开始增长。 这个标签的约束是上、左、右。 顺便说一句,我的标签有固定的行号,所以不用担心高度。


0
投票
  @IBInspectable var alignTop: Bool = false

  func setAlignTop() {
    let text = self.text!
    let lines = text.characters.split(separator: "\n").count
    if lines < self.numberOfLines {
      var newLines = ""
      for _ in 0..<(self.numberOfLines - lines) {
        newLines = newLines.appending("\n ")
      }
      self.text! = text.appending(newLines)
    }
  }

  override var text: String? {
    didSet {
      if alignTop {
        self.setAlignTop()
      }
    }
  }

0
投票

使用这是我的课程,您可以通过

alignment
更改文本
contentMode

支持大小写:.top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight

斯威夫特4

import Foundation
import UIKit

@IBDesignable
class UIAlignedLabel: UILabel {

    override func drawText(in rect: CGRect) {
        if let text = text as NSString? {
            func defaultRect(for maxSize: CGSize) -> CGRect {
                let size = text
                    .boundingRect(
                        with: maxSize,
                        options: NSStringDrawingOptions.usesLineFragmentOrigin,
                        attributes: [
                            NSAttributedStringKey.font: font
                        ],
                        context: nil
                    ).size
                let rect = CGRect(
                    origin: .zero,
                    size: CGSize(
                        width: min(frame.width, ceil(size.width)),
                        height: min(frame.height, ceil(size.height))
                    )
                )
                return rect

            }
            switch contentMode {
            case .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight:
                let maxSize = CGSize(width: frame.width, height: frame.height)
                var rect = defaultRect(for: maxSize)
                switch contentMode {
                    case .bottom, .bottomLeft, .bottomRight:
                        rect.origin.y = frame.height - rect.height
                    default: break
                }
                switch contentMode {
                    case .right, .topRight, .bottomRight:
                        rect.origin.x = frame.width - rect.width
                    default: break
                }
                super.drawText(in: rect)
            default:
                super.drawText(in: rect)
            }
        } else {
            super.drawText(in: rect)
        }
    }

}

0
投票

在Interface Builder中,只需设置高度<= some value instead of =. This will enable to text to start at the top and expand the height as needed. For example, I have a label with a height proportional to the size of the main view. So my height constraint looks like this: Height Constraint

© www.soinside.com 2019 - 2024. All rights reserved.