UIView的contentScaleFactor依赖于实现drawRect:? [英] UIView's contentScaleFactor depends on implementing drawRect:?
问题描述
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);
}
返回自我;
}
- (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:
。
这是一个错误还是一个错误特征?我知道我可以更改 didMoveToWindow
,如下所示修复它
- ( void)didMoveToWindow
{
if(self.window)
self.contentScaleFactor = self.window.screen.scale;
}
但默认行为仍然让我感到困惑。
如果我不画任何东西,你可能会问我为什么需要 contentScaleFactor
。那是因为我只是将 self.layer.contents
设置为现成的图像,然后用 contentStretch
拉伸图像。但是,除非 contentScaleFactor
设置正确,否则图像在Retina设备上无法正确拉伸,即使 @ 2x
图像用来。确切地说,它正常工作除非使用 @ 2x
图像。我想这是一个错误。
任何人都可以分享您对 contentScaleFactor
这样做的原因的见解吗?它仅适用于iOS 5吗?
大概,如果你不覆盖 drawRect:
然后UIKit知道 UIView
没有绘制任何东西,所以它需要(大概)快速的情况下,拥有一个内容规模为1的图层一旦你覆盖 drawRect:
,它就知道它需要设置一个具有正确内容比例的图层,如果你愿意,你可以绘制它。它不知道你在 drawRect:
中什么都不做,但它不能做出和以前一样的假设。
事实上,文档中提到了所有内容:
对于实现自定义drawRect:method的视图并且与窗口相关联,此属性的默认值是与当前显示视图的屏幕关联的比例因子。
为什么不直接覆盖 drawRect:
并在其中绘制图像?或者你可能可以逃脱目前正在做的事情并且有一个存根 drawRect:
。鉴于文档所说的内容,我认为假设它将继续工作并且是正确的行为是完全合理的。
I have stumbled on a weird thing. It looks like UIView
's contentScaleFactor
is always 1, even on Retina devices, unless you implement drawRect:
. Consider this code:
@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
On a Retina device it prints the following:
-[MyView initWithFrame:] 1 1 2
-[MyView didMoveToWindow] 1 1 2
If I add an empty implementation of drawRect:
like this:
- (void) drawRect: (CGRect) rect
{
}
it works as expected:
-[MyView initWithFrame:] 2 2 2
-[MyView didMoveToWindow] 2 2 2
So it looks like it doesn't really matter if the view is in any view hierarchy and what kind of screen it is displayed on. The only thing that does matter is if the view implements drawRect:
or not.
Is that a bug or a feature? I know I can change didMoveToWindow
as below to fix it
- (void) didMoveToWindow
{
if (self.window)
self.contentScaleFactor = self.window.screen.scale;
}
but the default behavior still bugs me.
You may ask why I need contentScaleFactor
at all if I don't draw anything. That's because I just set self.layer.contents
to a ready-made image and then stretch the image with contentStretch
. However, the image doesn't stretch properly on Retina devices unless contentScaleFactor
is set correctly, even though a @2x
image is used. To be precise, it works correctly unless a @2x
image is used. This is, I guess, a bug.
Can anyone share your insight into why contentScaleFactor
behaves this way? Is it specific to iOS 5 only?
Presumably, if you don't override drawRect:
then UIKit knows that a UIView
doesn't draw anything so it takes the (presumably) fast case of having a layer that has a content scale of 1. As soon as you override drawRect:
though, it knows it needs to set up a layer that is of the correct content scale that you can draw into if you want to. It doesn't know that you do nothing in drawRect:
though so it can't make the same assumption as before.
In fact all that is alluded to in the docs:
For views that implement a custom drawRect: method and are associated with a window, the default value for this property is the scale factor associated with the screen currently displaying the view.
Why don't you just override drawRect:
and in that, draw your image? Or you could probably get away with what you're currently doing and have a stub drawRect:
. Given what the docs say, I'd say that's perfectly reasonable to assume it's going to continue to work and is correct behaviour.
这篇关于UIView的contentScaleFactor依赖于实现drawRect:?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!