在缩放/变换上强制重绘 UIView 或 CALayer

Posted

技术标签:

【中文标题】在缩放/变换上强制重绘 UIView 或 CALayer【英文标题】:Force redraw of a UIView or CALayer on scale/transform 【发布时间】:2013-05-21 13:07:43 【问题描述】:

假设您有一个 UIViewCALayer 进行自己的(矢量)绘图,并且您希望它在任何尺寸下都保持清晰,即使在缩放视图或图层时也是如此。当它使用transform 属性缩放时,如何让它重绘?是强制更改bounds 而不是使用transform 的唯一方法吗?或者每一步都拨打setNeedsDisplay

为什么UIImageView 似乎表现不同(即它似乎总是适当地缩放其源图像,即使它使用transform 缩放并且bounds 没有改变)?是不是因为它是直接设置底层CALayercontent属性的唯一情况?

【问题讨论】:

问题到底是什么?当您处理可缩放矢量时,将在显示之前计算显示,而 UIImageView 将仅显示光栅图像。除非内容模式设置为缩放并且内容大于当前显示的大小,否则它肯定看起来不清晰。如果您正在缩放 rastor'd 矢量(渲染),那么您基本上只是在缩放成品。如果您只是缩放包含渲染矢量的视图,那么您正在缩放图像。 我知道,这就是问题所在,我希望重复调用drawRect,而不是仅仅放大初始光栅化。相反,UIImageView 不仅放大其初始边界的像素,还使用源图像的全分辨率。我想这意味着核心动画总是在变换中使用位图,当使用drawRect 时,位图的大小是边界,但是当内容是图像时,位图的大小就是图像的大小。这让我觉得我可以尝试使用大于 1 的 rasterizationScale.... 【参考方案1】:

如果CALayer 上的needsDisplayOnBoundsChange 在您的情况下还不够,您可以继承CALayer 并实现+ (BOOL)needsDisplayForKey:(NSString *)key 方法。示例:

+ (BOOL)needsDisplayForKey:(NSString *)key 
    if ([key isEqualToString:@"transform"]) 
        return YES;
    
    return [super needsDisplayForKey:key];

现在您的图层应该在每次transform 属性更改时重新绘制。如果您的绘图很广泛,这可能会导致动画性能问题。

【讨论】:

【参考方案2】:

对于基于矢量的图层,您可以使用CAShapeLayer。这个特殊的图层采用路径并会根据需要重新绘制以保持图层看起来清晰。

创建一个CGPathRef并将其分配给图层的path

shapeLayer.path = myPath;

【讨论】:

【参考方案3】:

您可以手动处理自定义视图的setTransform 方法。处理缩放事件的简化版本可能只是

-(void)setTransform:(CGAffineTransform)transform

    CGRect bounds = self.bounds;
    bounds.size.width *= transform.a;
    bounds.size.height *= transform.d;
    self.bounds = bounds;

这实际上只是调整视图的大小(并导致重绘),而不是拉伸图像。

【讨论】:

【参考方案4】:

您可以使用self.contentMode = UIViewContentMode.redraw

【讨论】:

有没有办法在 CALayer 本身上进行设置?

以上是关于在缩放/变换上强制重绘 UIView 或 CALayer的主要内容,如果未能解决你的问题,请参考以下文章

UIView 实时强制重绘(绘图应用)

在不调整大小或重绘的情况下扩展 UIView

UILabel 文本在应用缩放变换时被压缩/拉伸

防止在 UIScrollView 的最大/最小缩放时重绘屏幕

自定义视图在缩放后重绘时如何防止“反弹”效果?

UIView animateKeyframes 不起作用