4

Say you have a UIView or a CALayer that does its own (vector) drawing, and you want it to remain crisp at any size, even when scaling the view or layer. How can I make it redraw when it is scaled with the transform property? Is the only way to do to force a bounds change instead of using the transform? Or to call setNeedsDisplay at every step?

Why do UIImageView seem to behave differently (i.e. it seems to always scale its source image appropriately, even when it is scaled with transform and the bounds doesn't change)? Is it because it's the only case where the content property of the underlying CALayer is set directly?

Guillaume
  • 4,331
  • 2
  • 28
  • 31
  • What exactly is the question? When you are dealing with a scalable vector the display will be calculated prior to display while a UIImageView would be simply displaying a rastor image. Unless the content mode is set to scale and the content is larger than the current displayed size it would definitely not look crisp. If you are scaling a rastor'd vector (rendered) then you are basically just scaling the finished product. If you are simply scaling a view that contains a rendered vector then you are scaling an image. – Mark McCorkle May 21 '13 at 13:45
  • I know, and this is the problem, I would like `drawRect` to be called repeatedly, instead of just magnifying the initial rasterization. `UIImageView`, on the opposite, doesn't just magnify the pixels of its initial bounds, it uses the full resolution of the source image. I guess it means Core Animation always uses a bitmap in transforms and when `drawRect` is used the bitmap's size is the bounds, but when the content is an image the bitmap's size is the image's size. Which makes me think I could try to use `rasterizationScale` with a value greater than 1.... – Guillaume May 21 '13 at 15:08

4 Answers4

7

if needsDisplayOnBoundsChange on the CALayer is not enough in your case, you can subclass CALayer and implement the + (BOOL)needsDisplayForKey:(NSString *)key method. Example:

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

now your layer should be redrawn everytime the transform property changes. This might cause performance issues in animations if your drawing is extensive.

Jonathan Cichon
  • 4,396
  • 16
  • 19
1

For vector based layers, you can use CAShapeLayer. This specalised layer takes a path and will redraw as needed to keep the layer looking crisp.

Create a CGPathRef and assign it to the layer's path:

shapeLayer.path = myPath;
Graham Miln
  • 2,724
  • 3
  • 33
  • 33
1

You could use the self.contentMode = UIViewContentMode.redraw

JohnVanDijk
  • 3,546
  • 1
  • 24
  • 27
0

You could manually handle the setTransform method of your custom view. A simplified version for handling scaling events could simply be

-(void)setTransform:(CGAffineTransform)transform
{
    CGRect bounds = self.bounds;
    bounds.size.width *= transform.a;
    bounds.size.height *= transform.d;
    self.bounds = bounds;
}

This would just actually resize your view (and cause a redraw), rather than stretching an image.

micantox
  • 5,446
  • 2
  • 23
  • 27