UILabel之前底部对齐是很常见的布局需求,但是你的UILabel之间真的底部对齐了吗?
由于iOS UILabel文字底部都有留白的原因,而且文字的(字号/字体)不同底部留白的距离也不同,如果两个UILabel的文字字号不同,我们是很难将其完全对齐的。但是系统又没有提供得到文字底部留白距离的方法,我们只能通过微调frame的方法使它们肉眼看起来是对齐了。
然而好景不长,产品经理提出APP可调节字号的需求后,之前那种将就的做法彻底行不通了!所以不得不另辟蹊径,找出计算文字底部留白的方法。
- 首先我们发现Font有一些看似有用的属性
// Font attributes
@property(nonatomic,readonly,strong) NSString *familyName;//字体家族的名字
@property(nonatomic,readonly,strong) NSString *fontName;//字体的名字
@property(nonatomic,readonly) CGFloat pointSize;//字体大小
@property(nonatomic,readonly) CGFloat ascender;//基准线以上的高度
@property(nonatomic,readonly) CGFloat descender;//基准线以下的高度
@property(nonatomic,readonly) CGFloat capHeight;//大写X的高度
@property(nonatomic,readonly) CGFloat xHeight;//小写x的高度
@property(nonatomic,readonly) CGFloat lineHeight API_AVAILABLE(ios(4.0));//当前字体下的行高
@property(nonatomic,readonly) CGFloat leading;//行间距(一般为0)
- 具体代码运行结果可以更加清楚的说明各个属性的值,代码以14号字体为例
UIFont *font = [UIFont systemFontOfSize:14];
NSLog(@"font.pointSize = %f,font.ascender = %f,font.descender = %f,font.capHeight = %f,font.xHeight = %f,font.lineHeight = %f,font.leading = %f",font.pointSize,font.ascender,font.descender,font.capHeight,font.xHeight,font.lineHeight,font.leading);
运行结果如下
font.pointSize = 14.000000,
font.ascender = 13.330078,
font.descender = -3.376953,
font.capHeight = 9.864258,
font.xHeight = 7.369141,
font.lineHeight = 16.707031,
font.leading = 0.000000
其中可以很明显的看到:
设置的字体大小就是 pointSize
ascender - descender = lineHeight
- 实际行与行之间就是存在间隙的,间隙大小即为 lineHeight - pointSize,在富文本中设置行高的时候,其实际文字间的距离就是加上这个距离的:行间隙 = 行间距 + (lineHeight - pointSize)。(原来一直错误的理解两行文字间的距离就是行间距)
- 我们发现汉字和数字的的高度是不同的,但是行高相同,所以底部留白也就不同。
经过测试我们找出了计算数字底部留白的公式:
- (CGFloat)getNumBottomGapByFont:(UIFont *)font {
return roundf(-font.descender);//roundf四舍五入取整
}
计算汉字底部留白的公式:
- (CGFloat)getChineseBottomGapByFont:(UIFont *)font {
return roundf((font.lineHeight - font.pointSize) / 2.0 + font.pointSize / 20.0);//在(font.lineHeight - font.pointSize) / 2.0的基础上每增加10个字号留白增加1像素,所以加上font.pointSize / 20.0
}
- 实际应用中,例如UILabel A、B、C需求底部对齐,我们根据A的frame和bottomGap(底部留白),调整B、C的originY即可(如果UILabel为纯数字用- (CGFloat)getNumBottomGapByFont:(UIFont *)font函数,如果有汉字用- (CGFloat)getChineseBottomGapByFont:(UIFont *)font函数):
B.bottomGap = [self getNumBottomGapByFont:B.font];
B.frame = CGRectMake(B.frame.origin.x, B.frame.origin.y + B.bottomGap - A.bottomGap, B.frame.size.width, B.frame.size.height);
C.bottomGap = [self getNumBottomGapByFont:C.font];
C.frame = CGRectMake(C.frame.origin.x, C.frame.origin.y + C.bottomGap - A.bottomGap, C.frame.size.width, C.frame.size.height);
或者我们计算UILabel高度的时候直接去掉上下空隙,纯数字label:
label.frame = CGRectMake(x, y, width, label.font.ascender + label.font.descender);
有汉字的label(每增加10个字号留白增加1像素,所以减去font.pointSize / 20.0):
label.frame = CGRectMake(x, y, width, label.font.pointSize - label.font.pointSize / 20.0);