在UILabel中垂直顶部对齐文本
技术背景
在iOS开发中,UILabel 本身没有直接设置垂直对齐的属性,但在实际开发中,我们可能需要将文本垂直顶部对齐。本文将介绍多种实现 UILabel 文本垂直顶部对齐的方法。
实现步骤
方法一:使用 sizeToFit
- 单行文本:直接调用
sizeToFit方法,该方法会调整标签的大小以适应其内容。
[myLabel sizeToFit];
- 多行文本:先将
numberOfLines设置为0(表示不限行数),再调用sizeToFit方法。
myLabel.numberOfLines = 0;
[myLabel sizeToFit];
方法二:自定义 UILabel 子类
创建一个继承自 UILabel 的子类,重写 drawTextInRect: 方法。
Objective-C 实现
@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
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)
}
}
Swift 4.2 实现
class VerticalTopAlignLabel: UILabel {
override func drawText(in rect:CGRect) {
guard let labelText = text else { return super.drawText(in: rect) }
let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
var newRect = 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)
}
}
方法三:使用 StackView
将 UILabel 嵌入到 StackView 中,并在属性检查器中设置 Axis 为 Horizontal,Alignment 为 Top。
方法四:使用扩展方法
创建一个 UILabel 的扩展,添加 alignTop 和 alignBottom 方法。
// UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end
// 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
使用时,设置文本后调用相应方法:
[myLabel alignTop];
方法五:使用 UITextField 替代
如果不需要 UILabel 的交互性,可以使用 UITextField 替代,并设置垂直对齐方式。
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // 禁止交互
方法六:自适应 UI 约束设置
对于 iOS 8 及以后的版本,可以在 Storyboard 中设置 UILabel 的属性和约束来实现垂直对齐。
- 设置
noOfLines = 0。 - 调整
UILabel的左、右、上边界约束。 - 将
Content Compression Resistance Priority For Vertical设置为1000,使垂直优先级高于水平优先级。
核心代码
上述实现步骤中已经包含了核心代码,这里再次强调一些关键代码片段。
使用 sizeToFit 实现多行文本对齐
myLabel.numberOfLines = 0;
[myLabel sizeToFit];
自定义 UILabel 子类实现垂直顶部对齐(Swift 4.2)
class VerticalTopAlignLabel: UILabel {
override func drawText(in rect:CGRect) {
guard let labelText = text else { return super.drawText(in: rect) }
let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
var newRect = 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)
}
}
最佳实践
- 简单场景:如果只是简单的单行或多行文本对齐,优先使用
sizeToFit方法。 - 复杂场景:对于需要自定义布局和样式的场景,建议使用自定义
UILabel子类的方法。 - Storyboard 场景:在使用 Storyboard 进行布局时,使用
StackView或约束设置可以更方便地实现垂直对齐。
常见问题
使用 sizeToFit 时文本对齐问题
当文本为居中或右对齐时,使用 sizeToFit 可能会导致布局问题。可以在 sizeToFit 后手动调整标签的宽度。
myLabel.textAlignment = NSTextAlignmentCenter;
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
CGRect myFrame = myLabel.frame;
// 调整框架宽度
myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
myLabel.frame = myFrame;
使用自动布局时 sizeToFit 无效
如果 UILabel 包含在使用自动布局的 ViewController 的 view 中,将 sizeToFit 调用放在 viewDidLoad 中可能无效。可以将其放在 viewDidLayoutSubviews 中。
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[myLabel sizeToFit];
}
UILabel文本垂直顶部对齐方法
3万+

被折叠的 条评论
为什么被折叠?



