垂直对齐 UILabel 中的文本(注意:使用 AutoLayout)
Vertically align text within a UILabel (Note : Using AutoLayout)
我正在复制 Question 之前问过的相同问题。
我已经尝试了给出的解决方案,但无法解决,因为 sizetofit 在我使用 Autolayout 时无效。
预期的显示如下。
您可以通过删除最小高度来做到这一点。
如果您需要标签下方其他内容的最小高度,那么您可以使用根据标签内容调整大小但使用最小值的容器视图。
你可以试试 if 按钮 [button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
编辑:
如果你只想使用标签,你可以试试这个:
自动布局仅适用于 edges/sizes 控制器,不适用于控制器 content.so 使用自动布局在第一行顶部显示标签文本不是一个好主意。
根据我的说法,sizetofit 是这样做的最佳选择。
编辑
在我原来的回答中,我使用的是标签的段落样式。事实证明,对于多行标签,这实际上可以防止标签成为多行。结果我把它从计算中删除了。在 Github
中查看更多相关信息
对于那些更习惯使用开放源代码的人,请务必查看 TTTAttributedLabel,您可以在其中将标签的文本对齐方式设置为 TTTAttributedLabelVerticalAlignmentTop
诀窍是继承 UILabel
并覆盖 drawTextInRect
。然后强制在标签边界的原点绘制文本。
这是您现在可以使用的简单实现:
Swift
@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
}
}
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
}
}
Objective-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,所以您可以将这个标签添加到情节提要中并观察它的运行,这就是我的样子
您可以使用 UITextView 代替 UILabel:
取消选中 "Scrolling enabled"
取消选中 "Editable"
取消选中 "Selectable"
将背景颜色设置为 ClearColor
我使用了@Daniel Golasko 的解决方案,只要 UILabel 中的文本比 UILabel 可以包含的文本长,文本就会开始向下移动,而不是保持与顶部对齐。
我更改了这一行以确保文本正确对齐
[super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),MIN(ceilf(labelStringSize.height), self.frame.size.height))];
如果您不受固定大小的 UILabel 的限制,而不是在 UILabel 中对齐文本,只需在给定标签上使用 ≥ 约束来更改它的大小。
这是使用自动布局的最优雅的解决方案。不要忘记将 numberOfLines 设置为零。
我遇到了同样的问题,我就是这样解决的。我刚刚在标签的属性检查器下编辑了基线。将其设置为 "Align Centers".
相反,我将底部 Space 常量更改为优先级 @250 并解决了我的问题。我的标签的高度常数为 <= constant
我有一个类似的问题,其中有 3 个标签。中间的标签可以有比其他两个标签更长的文本,因此它的高度可以变得更大。
像这样:
我将中间标签的底部 space 约束设置为 >= 底部标签。
这解决了我的问题。
对我来说,我没有设置高度限制,文本总是从标签的顶部开始增长。
这个标签的约束是上、左、右。
顺便说一句,我的标签有固定的行号,所以不用担心高度。
@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()
}
}
}
这里是 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
}
}
对于标签高度不需要恒定的情况,有一个简单的解决方案:将 Label
放在 Stack View
中。请务必将前导和尾随常量添加到 Stack View
。这是如何在情节提要中执行此操作的屏幕截图:
使用 这个我的 class,你可以通过 contentMode
更改文本 alignment
。
supported case: .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight
Swift4
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)
}
}
}
Swift 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)
}
}
在 Interface Builder 中,只需让高度 <= 某个值而不是 =。这将使文本从顶部开始并根据需要扩展高度。例如,我有一个标签,其高度与主视图的大小成正比。所以我的身高限制是这样的:
Height Constraint
我正在复制 Question 之前问过的相同问题。 我已经尝试了给出的解决方案,但无法解决,因为 sizetofit 在我使用 Autolayout 时无效。
预期的显示如下。
您可以通过删除最小高度来做到这一点。
如果您需要标签下方其他内容的最小高度,那么您可以使用根据标签内容调整大小但使用最小值的容器视图。
你可以试试 if 按钮 [button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
编辑:
如果你只想使用标签,你可以试试这个:
自动布局仅适用于 edges/sizes 控制器,不适用于控制器 content.so 使用自动布局在第一行顶部显示标签文本不是一个好主意。 根据我的说法,sizetofit 是这样做的最佳选择。
编辑
在我原来的回答中,我使用的是标签的段落样式。事实证明,对于多行标签,这实际上可以防止标签成为多行。结果我把它从计算中删除了。在 Github
中查看更多相关信息对于那些更习惯使用开放源代码的人,请务必查看 TTTAttributedLabel,您可以在其中将标签的文本对齐方式设置为 TTTAttributedLabelVerticalAlignmentTop
诀窍是继承 UILabel
并覆盖 drawTextInRect
。然后强制在标签边界的原点绘制文本。
这是您现在可以使用的简单实现:
Swift
@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
}
}
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
}
}
Objective-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,所以您可以将这个标签添加到情节提要中并观察它的运行,这就是我的样子
您可以使用 UITextView 代替 UILabel:
取消选中 "Scrolling enabled"
取消选中 "Editable"
取消选中 "Selectable"
将背景颜色设置为 ClearColor
我使用了@Daniel Golasko 的解决方案,只要 UILabel 中的文本比 UILabel 可以包含的文本长,文本就会开始向下移动,而不是保持与顶部对齐。
我更改了这一行以确保文本正确对齐
[super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),MIN(ceilf(labelStringSize.height), self.frame.size.height))];
如果您不受固定大小的 UILabel 的限制,而不是在 UILabel 中对齐文本,只需在给定标签上使用 ≥ 约束来更改它的大小。
这是使用自动布局的最优雅的解决方案。不要忘记将 numberOfLines 设置为零。
我遇到了同样的问题,我就是这样解决的。我刚刚在标签的属性检查器下编辑了基线。将其设置为 "Align Centers".
相反,我将底部 Space 常量更改为优先级 @250 并解决了我的问题。我的标签的高度常数为 <= constant
我有一个类似的问题,其中有 3 个标签。中间的标签可以有比其他两个标签更长的文本,因此它的高度可以变得更大。
像这样:
我将中间标签的底部 space 约束设置为 >= 底部标签。
这解决了我的问题。
对我来说,我没有设置高度限制,文本总是从标签的顶部开始增长。 这个标签的约束是上、左、右。 顺便说一句,我的标签有固定的行号,所以不用担心高度。
@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()
}
}
}
这里是 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
}
}
对于标签高度不需要恒定的情况,有一个简单的解决方案:将 Label
放在 Stack View
中。请务必将前导和尾随常量添加到 Stack View
。这是如何在情节提要中执行此操作的屏幕截图:
使用 这个我的 class,你可以通过 contentMode
更改文本 alignment
。
supported case: .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight
Swift4
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)
}
}
}
Swift 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)
}
}
在 Interface Builder 中,只需让高度 <= 某个值而不是 =。这将使文本从顶部开始并根据需要扩展高度。例如,我有一个标签,其高度与主视图的大小成正比。所以我的身高限制是这样的: Height Constraint