我没有答案,但是我做了一些研究并想分享一下。我使用Xtrace,它可以让您跟踪Objective-C方法调用,尝试弄清楚UILabel正在做什么。我从Xtrace git存储库中添加了Xtrace.h
和Xtrace.mm
到Christian的UILabel演示项目中。在RootViewController.m
中,我添加了#import "Xtrace.h"
,然后尝试使用各种跟踪过滤器。将以下内容添加到RootViewController的loadView
中:
[Xtrace includeMethods:@"drawWithRect|drawInRect|drawTextInRect"]
[Xtrace traceClassPattern:@"String|UILabel|AppleLabel" excluding:nil]
给我这个输出:
| [<AppleLabel 0x7fedf141b520> drawTextInRect:{{0, 0}, {187.5, 333.5}}]
| [<NSConcreteMutableAttributedString 0x7fedf160ec30>/NSAttributedString drawInRect:{{0, 156.5}, {187.5, 333.5}}]
| [<UILabel 0x7fedf1418dc0> drawTextInRect:{{0, 0}, {187.5, 333.5}}]
| [<UILabel 0x7fedf1418dc0> _drawTextInRect:{{0, 0}, {187.5, 333.5}} baselineCalculationOnly:0]
| [<__NSCFConstantString 0x1051d1db0>/NSString drawWithRect:{{0, 156.3134765625}, {187.5, 20.287109375}} options:1L attributes:<__NSDictionaryM 0x7fedf141ae00> context:<NSStringDrawingContext 0x7fedf15503c0>]
我正在使用Xcode 7.0 beta和iOS 9.0模拟器运行此程序。
我们可以看到,苹果的实现并没有将drawInRect:
发送到NSAttributedString,而是将drawWithRect:options:attributes:
发送到NSString。我猜这两个方法最终会做相同的事情。
我们还可以看到计算出来的Y偏移量是多少。在滑块的初始位置,它是156.3134765625。有趣的是,它不是某个舍入整数值或0.25的倍数等等,否则这就是跳跃性的原因。
我们还看到UILabel发送了20.287109375作为高度,这与self.attributedText.size.height
计算出来的值相同。所以它似乎在使用那个值,尽管我还没有追踪这个调用(也许它直接使用Core Text?)。
所以这就是我卡住的地方。一直在试图查看UILabel计算和显然的公式"labelYOffset = (boundsHeight - labelHeight) / 2.0"之间的差异,但我找不到一致的模式。
更新1.
因此,我们可以将这个难以捉摸的Y偏移量建模为
labelYOffset = (boundsHeight - labelHeight)/ 2.0 + error
我们要弄清楚的是error
是什么。让我们像科学家一样研究它。这里是我将滑块拖到最后,然后拖回开头时的Xtrace输出。我还在每次滑块变化时添加了一个NSLog,这有助于分离条目。我编写了一个Python脚本来绘制标签高度与误差之间的关系。
有趣。我们发现错误存在一定的线性关系,但在某些点上它们会奇怪地跳跃到其他行,如果你明白我的意思的话。这是怎么回事?我会失眠直到解决这个问题。 :)
UILabel
中犯了什么错误。 - Christian SchnorrUILabel
的默认drawTextInRect:
并添加一个自定义属性到所有的UILabel
中,以便定义是否使用你自己的实现还是默认实现。这样你就可以在任何UILabel
实例中使用自己的绘制方式,例如:通过使用label.useCustomDrawing = YES;
。-- 你也可以创建一个简单的UILabel
子类(不需要存储属性),然后在运行时替换要修改的标签的类(无法自己实例化):object_setClass(evilLabel, MyCoolLabel.class);
- fluidsonic