如何在 iOS 上对齐 UILabels 中不同字体大小的文本基线?

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

历史性问题。

lastBaselineAnchor
现在为此目的而存在。


我需要对齐 UILabels 中文本的基线。我目前正在做的是对齐包含文本的 UILabels 的基线,并且当两个标签中的文本字体大小不同时,这会导致对齐的 UILabels 基线但未对齐的文本基线(未对齐一小部分,但仍然未对准)。这些标签包含在自定义 UIView 子类中,因此

self
指的是包含的 UIView。

这是相关代码

[self.mySmallLabel sizeToFit];
[self.myBigLabel sizeToFit];

self.mySmallLabel.frame = CGRectMake(0,     
                                     self.bounds.size.height - self.mySmallLabel.bounds.size.height, 
                                     self.mySmallLabel.bounds.size.width, 
                                     self.mySmallLabel.bounds.size.height);

self.myBigLabel.frame = CGRectMake(self.mySmallLabel.frame.origin.x + self.mySmallLabel.bounds.size.width, 
                                   self.bounds.size.height - self.myBigLabel.bounds.size.height, 
                                   self.myBigLabel.bounds.size.width, 
                                   self.myBigLabel.bounds.size.height);
[self.mySmallLabel sizeToFit];
[self.myBigLabel sizeToFit];

此代码会导致下面链接的图像中的对齐。

Misalignemnt

正如您所看到的,即使 UILabel 基线对齐,文本的基线也有很小的偏差。如何动态对齐文本的基线(因为字体大小可能在运行时发生变化)?

iphone ios ios4
5个回答
24
投票

我在几个不同的地方使用了这个答案,但基线有时在视网膜显示屏上有一个像素的偏差。下面的代码片段说明了屏幕的比例:

[majorLabel sizeToFit];
[minorLabel sizeToFit];

CGRect changedFrame = minorLabel.frame;
changedFrame.origin.x = CGRectGetWidth(majorLabel.frame);

const CGFloat scale = [UIScreen mainScreen].scale;
const CGFloat majorLabelBaselineInSuperView = CGRectGetMaxY(majorLabel.frame) + majorLabel.font.descender;
const CGFloat minorLabelBaselineInOwnView = CGRectGetHeight(minorLabel.frame) + minorLabel.font.descender;
changedFrame.origin.y = ceil((majorLabelBaselineInSuperView - minorLabelBaselineInOwnView) * scale) / scale;

minorLabel.frame = changedFrame;

8
投票

通过在简单的计算中使用 UIFont 上升值,您可以为任何一对 UILabel 获得像素完美的基线对齐。方法如下:

[majorLabel sizeToFit];
[minorLabel sizeToFit];

CGRect changedFrame = minorLabel.frame;
changedFrame.origin.y = ceilf(majorLabel.frame.origin.y + (majorLabel.font.ascender - minorLabel.font.ascender));
minorLabel.frame = changedFrame;
使用

ceilf()
是因为 font.ascender 值可能是小数。

我已经在视网膜和非视网膜设备上对此进行了测试,结果非常好。由于您的需求可能会有所不同,因此省略了两个标签在 x 轴上的相对定位。如果您需要快速解释 UIFont 上升器是什么(以及其他 UIFont 信息),请查看这篇清晰、简洁的文章


8
投票

lastBaselineAnchor
正是为了这个目的。


iOS9之后。 通过自动布局,UILabel 有一个名为:lastBaselineAnchor 的锚点。 例如:

hintLabel.lastBaselineAnchor.constraint(equalTo: titleLabel.lastBaselineAnchor).isActive = true
    

3
投票
我想自己做这件事(刚才),并在一个“几乎相同的问题”上找到了答案。但这不是简单的解决方案,我们必须进行数学计算。

我只需要使用 2 个不同的标签来完成它,并且我在 UIView

的子类中完成它。

- (void)layoutSubviews {
    [majorLabel sizeToFit];
    [minorLabel sizeToFit];

    CGRect changedFrame = minorLabel.frame;
    changedFrame.origin.x = majorLabel.frame.size.width;
    changedFrame.origin.y = (majorLabel.frame.size.height + majorLabel.font.descender) - (minorLabel.frame.size.height + minorLabel.font.descender);
    minorLabel.frame = changedFrame;
}

使用自动布局,变得更加容易。
选择您想要对齐的 2 个标签,然后转到对齐工具。选择“底边”/“顶边”/基线 

-2
投票
© www.soinside.com 2019 - 2024. All rights reserved.