我偶然发现了一件奇怪的事情。看起来UIView
的contentScaleFactor
总是1,即使在Retina设备上也是如此,除非实现drawRect:
。考虑这个代码:
@interface MyView : UIView
@end
@implementation MyView
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame: frame];
if (self) {
NSLog(@"%s %g %g %g", __PRETTY_FUNCTION__, self.contentScaleFactor, self.layer.contentsScale, [UIScreen mainScreen].scale);
}
return self;
}
- (void) didMoveToWindow
{
if (self.window)
NSLog(@"%s %g %g %g", __PRETTY_FUNCTION__, self.contentScaleFactor, self.layer.contentsScale, [UIScreen mainScreen].scale);
}
@end
在Retina设备上,它会打印以下内容:
-[MyView initWithFrame:] 1 1 2
-[MyView didMoveToWindow] 1 1 2
如果我添加drawRect:
的空实现,如下所示:
- (void) drawRect: (CGRect) rect
{
}
它按预期工作:
-[MyView initWithFrame:] 2 2 2
-[MyView didMoveToWindow] 2 2 2
因此,视图是否在任何视图层次结构中以及显示在什么样的屏幕上似乎都无关紧要。唯一重要的是视图是否实现drawRect:
。
这是bug还是功能?我知道我可以更改didMoveToWindow
如下以修复
- (void) didMoveToWindow
{
if (self.window)
self.contentScaleFactor = self.window.screen.scale;
}
但默认行为仍然困扰着我。
如果我什么都不画,你可能会问我为什么需要contentScaleFactor
。这是因为我只是将self.layer.contents
设置为一个现成的图像,然后用contentStretch
拉伸图像。但是,除非正确设置了contentScaleFactor
,否则即使使用了@2x
图像,图像在Retina设备上也无法正确拉伸。准确地说,除非使用@2x
图像,否则它可以正常工作。我想,这是一个bug。
有人能分享你对contentScaleFactor
为什么会这样做的见解吗?它是否仅适用于iOS 5?
假设,如果您不覆盖drawRect:
,那么UIKit知道UIView
不会绘制任何内容,因此它采用(假设)具有内容比例为1的层的快速情况。然而,一旦你覆盖drawRect:
,它就知道它需要建立一个具有正确内容规模的层,如果你想的话,它可以绘制到这个层中。但它不知道你在drawRect:
中什么都不做,所以它不能做出与以前相同的假设。
事实上,所有这些都在文件中提到:
对于实现自定义drawRect:方法并与窗口关联的视图,此属性的默认值是与当前显示视图的屏幕关联的比例因子。
为什么你不直接覆盖drawRect:
,然后在其中绘制你的图像?或者,你可能会逃脱目前正在做的事情,并拥有一个存根drawRect:
。根据医生的说法,我认为这是完全合理的,可以认为它会继续发挥作用,并且是正确的行为。
本地绘图技术,如Core Graphics,会将当前比例因子考虑在内。例如,如果某个视图实现了drawRect:方法,UIKit会自动将该视图的比例因子设置为屏幕的比例因子。此外,UIKit会自动修改绘图过程中使用的任何图形上下文的当前变换矩阵,以考虑视图的比例因子。因此,您在drawRect:方法中绘制的任何内容都会根据底层设备的屏幕进行适当缩放。