简体   繁体   English

即使使用UIViewContentModeScaleAspectFill也可以调用自定义UIView drawRect

[英]Custom UIView drawRect is called even with UIViewContentModeScaleAspectFill

I'm having the following issue. 我遇到以下问题。

Suppose I have my own image view class (to make it easy I've trimmed all the code and just included only the code that is causing the issue). 假设我有自己的图像视图类(为简便起见,我修剪了所有代码,仅仅包含引起问题的代码)。 That class inherits from UIView and overrides drawRect . 该类继承自UIView并重写drawRect Here is how my drawRect looks (the code is in Xamarin, but it's easy to understand) 这是我的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);
        }
    }

This code simply draws the image set to Image property in a way which simulates UIImageView 's aspect fill option by calculating the rect which will display the image in aspect fill mode using this line of code getAspectFillRect(rect, Image.Size); 这段代码通过计算rect来模拟UIImageView的宽高比选项,从而简单地绘制设置为Image属性的图像,方法是使用此行代码getAspectFillRect(rect, Image.Size);计算将以宽高比模式显示图像的getAspectFillRect(rect, Image.Size);

I also have UICollectionView with custom layout and custom cells. 我也有带有自定义布局和自定义单元格的UICollectionView Each UICollectionViewCell UI is defined in an xib file, there I have all the necessary constraints set and I there I also have my custom view for displaying images. 每个UICollectionViewCell UI在一个xib文件中定义,在那里我设置了所有必要的约束,并且在这里我也有用于显示图像的自定义视图。 For that view in interface builder I've set content mode to "Aspect Fill". 对于界面构建器中的该视图,我已将内容模式设置为“长宽比填充”。 The custom UICollectionViewLayout is made in a way that cell expands (you'll see the example shortly). 自定义UICollectionViewLayout是通过单元格扩展的方式制作的(稍后将看到示例)。 So the image inside the cell should also scale, and as I've set "Aspect Fill" option, it shouldn't call drawRect of my custom view, rather it should just scale already drawn content. 因此,单元格内的图像也应缩放,并且当我设置了“ Aspect Fill”选项时,它不应调用自定义视图的drawRect ,而应缩放已绘制的内容。 But that is not the case! 但事实并非如此!

LOOK HERE to see the video which demonstrates what happens. 在这里查看观看演示事件的视频。 You may see that the image inside is not growing together with the cell. 您可能会看到里面的图像没有与单元格一起增长。 The problem is that before ever the cell expanding animation begins drawRect of my custom UIView is called with the rect which will eventually be established after the animation. 问题在于,在单元扩展动画开始之前,我的自定义UIView drawRect会通过rect调用,而rect将最终在动画之后建立。 So I get a jerky animation. 所以我得到了一个生涩的动画。 In my custom layout code I just call LayoutIfNeeded after updating the constraints of the cell. 在我的自定义布局代码中,我在更新单元格的约束后仅调用LayoutIfNeeded I don't call setNeedsDisplay , so I don't get why my drawRect is called. 我不叫setNeedsDisplay ,所以我不知道为什么我的drawRect被调用。

For experiment I replaced my custom image view with UIImageView , I set it's content mode to "Aspect Fill", and LOOK HERE what happened. 为了进行实验,我将自定义图像视图替换为UIImageView ,将其内容模式设置为“ Aspect Fill”,然后在此处查找发生了什么。 YEAH! 是的 It worked. 有效。 So I suppose the issue is not in the custom UICollectionView layout, rather in my custom image drawing class. 因此,我认为问题不在定制UICollectionView布局中,而在我的定制图像绘图类中。

What I should take into account?? 我应该考虑什么? How I should handle this case? 我应该如何处理这种情况? Any Ideas? 有任何想法吗? Thanks! 谢谢!

DrawRect will be called whenever the system "feels" it should call it. 只要系统“感觉”到它, DrawRect就会被调用。 Regardless if you call SetNeedsDisplay or not. 无论是否调用SetNeedsDisplay

Now, setting ContentMode to ScaleAspectFill does not mean that DrawRect will not be called. 现在,将ContentMode设置为ScaleAspectFill并不意味着不会调用DrawRect In fact, from Apple docs here : 事实上,从苹果的文档在这里

Instead of redrawing the contents of the view every time, you can use this property to specify that you want to scale the contents (either with or without distortion) or pin them to a particular spot on the view. 不必每次都重新绘制视图的内容,而是可以使用此属性来指定要缩放的内容(带有或不带有失真)或将它们固定到视图上的特定位置。

This means that, if you don't want to go through the hassle of drawing the contents yourself, just set the ContentMode property. 这意味着,如果您不想自己绘制内容的麻烦,只需设置ContentMode属性。 In your example, you are using DrawRect to draw. 在您的示例中,您正在使用DrawRect进行绘制。

Now, the fact that DrawRect is called before the animation starts, but with the target value for Bounds (or Frame ?) means that the target value of these properties is set before the change finishes. 现在,事实上在动画开始之前调用了DrawRect ,但是具有Bounds (或Frame ?)的目标值的事实意味着,这些属性的目标值是在更改完成之前设置的。 During an animation, these properties do not change. 在动画期间,这些属性不会更改。 Note during . 期间注意。 A Bounds ' or Frame 's value will not change through all the values of an ongoing transition. BoundsFrame的值不会在进行中的过渡的所有值中改变。 It only knows "start" and "end". 它只知道“开始”和“结束”。

What would happen in your app if DrawRect was not called before the animation start, but was called after animation end? 如果在动画开始之前调用DrawRect ,但在动画结束之后调用了DrawRect则在应用程序中会发生什么? Well, the cell would resize along with its subview, but your image would remain small throughout the animation and snap to the large size after the animation finished. 好了,单元格将随其子视图一起调整大小,但是您的图像在整个动画中将保持较小,并在动画结束后捕捉到较大的尺寸。 So it's one way or the other. 因此,这是一种方法。

Solutions: 解决方案:

  • Use the UIImageView. 使用UIImageView。
  • If you do need to use a custom view, use a UIImageView on that to display your image. 如果确实需要使用自定义视图,请在该视图上使用UIImageView来显示图像。
  • Draw your image on a custom CALayer and add that layer on your custom view's Layer. 在自定义CALayer上绘制图像,然后将该层添加到自定义视图的“图层”上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM