即使使用 UIViewContentModeScaleAspectFill 也会调用自定义 UIView drawRect
Posted
技术标签:
【中文标题】即使使用 UIViewContentModeScaleAspectFill 也会调用自定义 UIView drawRect【英文标题】:Custom UIView drawRect is called even with UIViewContentModeScaleAspectFill 【发布时间】:2014-09-25 13:15:54 【问题描述】:我遇到了以下问题。
假设我有自己的图像视图类(为方便起见,我修剪了所有代码,只包含导致问题的代码)。该类继承自UIView
并覆盖drawRect
。这是我的drawRect
的外观(代码在 Xamarin 中,但很容易理解)
public override void Draw(RectangleF rect)
base.Draw(rect);
CGContext context = UIGraphics.GetCurrentContext();
if (Image != null)
var imageRect = getAspectFillRect(rect, Image.Size);
context.DrawImage(imageRect, Image.CGImage);
else
this.BackgroundColor.SetFill();
context.FillRect(this.Bounds);
这段代码简单地绘制设置为Image
属性的图像,通过计算矩形来模拟UIImageView
的方面填充选项,该矩形将使用这行代码getAspectFillRect(rect, Image.Size);
以方面填充模式显示图像
我也有 UICollectionView
自定义布局和自定义单元格。每个UICollectionViewCell
UI 都在一个xib 文件中定义,在那里我设置了所有必要的约束,并且我还拥有用于显示图像的自定义视图。对于界面生成器中的该视图,我已将内容模式设置为“Aspect Fill”。自定义UICollectionViewLayout
以单元格扩展的方式制作(您将很快看到该示例)。所以单元格内的图像也应该缩放,并且因为我设置了“Aspect Fill”选项,它不应该调用我的自定义视图的drawRect
,而应该只是缩放已经绘制的内容。但事实并非如此!
LOOK HERE 观看演示所发生情况的视频。
您可能会看到里面的图像没有与细胞一起生长。问题是,在我的自定义UIView
的单元格扩展动画开始drawRect
之前,使用最终将在动画之后建立的矩形进行调用。所以我得到了一个生涩的动画。在我的自定义布局代码中,我只是在更新单元格的约束后调用LayoutIfNeeded
。我不打电话给setNeedsDisplay
,所以我不明白为什么我的drawRect
会被调用。
为了实验,我用UIImageView
替换了我的自定义图像视图,我将它的内容模式设置为“Aspect Fill”,LOOK HERE 发生了什么。是的!有效。所以我想问题不在于自定义UICollectionView
布局,而在于我的自定义图像绘制类。
我应该考虑什么?我应该如何处理这种情况?有任何想法吗? 谢谢!
【问题讨论】:
【参考方案1】:DrawRect
将在系统“感觉”它应该调用它时被调用。不管你是否打电话给SetNeedsDisplay
。
现在,将ContentMode
设置为ScaleAspectFill
并不意味着DrawRect
将不会 被调用。事实上,来自 Apple 文档here:
不用每次都重绘视图的内容,你可以使用 这个属性来指定你想要缩放的内容(或者 有或没有失真)或将它们固定在 查看。
这意味着,如果您不想自己绘制内容的麻烦,只需设置ContentMode
属性。在您的示例中,您正在使用DrawRect
进行绘图。
现在,DrawRect
在动画开始之前被调用,但目标值为Bounds
(或Frame
?)意味着这些属性的目标值为在更改完成之前设置。在动画期间,这些属性不会改变。注意期间。 Bounds
' 或 Frame
的值不会随着正在进行的转换的所有值而改变。它只知道“开始”和“结束”。
如果DrawRect
在动画开始前没有被调用,但在动画结束后被调用,你的应用会发生什么?好吧,单元格将随其子视图一起调整大小,但您的图像将在整个动画过程中保持较小,并在动画完成后捕捉到大尺寸。所以这是一种或另一种方式。
解决方案:
使用 UIImageView。 如果您确实需要使用自定义视图,请在其上使用 UIImageView 来显示您的图像。 在自定义 CALayer 上绘制图像并将该图层添加到自定义视图的图层上。【讨论】:
你好,迪米特里斯。感谢你的回答。我也在考虑绘制所有内容并将其设置为 UIImageView 的图像。但对我来说,这不是最好的解决方案。在我的情况下,使用 UIImageView 不是解决方案。我认为第三个解决方案与我的相同,不是吗?我认为它会再次像我的生涩动画一样工作。我认为如果 UIImageView 正在工作,那么应该有一种方法可以构建一个在当前情况下可以像 UIImageView 一样工作的类。你怎么看? 不,选项 #3 将起作用。在层上做这件事实际上是 UIImageView 正在做的事情。无需创建自己的图像视图。但是,它需要一些工作来根据 UICollectionView 的动画进行相应的调整。从一个简单的例子开始:在 CALayer 上绘制一个图像并使用 CABasicAnimation 调整它的大小,看看会发生什么。请记住,您必须考虑“开始”和“结束”值。以上是关于即使使用 UIViewContentModeScaleAspectFill 也会调用自定义 UIView drawRect的主要内容,如果未能解决你的问题,请参考以下文章
即使我在 laravel 中使用 updateorcreate 方法,为啥还要复制数据
为啥 isConfiguration:compatibleWithStoreMetadata 会返回 yes,即使使用了映射模型?