Search code examples
iosobjective-cswiftuiviewcalayer

What is the property "contentsCenter" mean in CALayer Class?


this is an origin image. origin image

I set it like follow:

self.layerView.contentsCenter = CGRectMake(0.25, 0.25, 0.5, 0.5);

then display like follow: change image

but according to the explain by Apple, it should be scaled instead of disappear, you can see the center part of the change image disappear.

what happened?

can you help me , thank you.


complete code:

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic,strong) UIView *erView;
@property (nonatomic,strong) CALayer *layerView;
@end

@implementation ViewController

#pragma mark - life cycle

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setUpView];
}

#pragma mark - set up

- (void)setUpView{
    self.view.backgroundColor = [UIColor redColor];
    self.erView = [[UIView alloc] initWithFrame:CGRectMake(50, 100, 200, 200)];
    [self.view addSubview:self.erView];
    self.layerView = [CALayer layer];
    self.layerView.frame = CGRectMake(0, 0, 200, 200);
    self.layerView.backgroundColor = [UIColor blueColor].CGColor;
    [self.erView.layer addSublayer:self.layerView];
    UIImage *image = [UIImage imageNamed:@"picture"];
    [self addSpriteImage:image withContentRect:CGRectMake(0, 0, 1, 1) toLayer:self.layerView];
    self.layerView.contentsCenter = CGRectMake(0.25, 0.25, 0.5, 0.5);
}

- (void)addSpriteImage:(UIImage *)image withContentRect:(CGRect)rect toLayer:(CALayer *)layer{
    layer.contents = (__bridge id)image.CGImage;
    layer.contentsGravity = kCAGravityResizeAspect;
    layer.contentsRect = rect;
}


@zrzka,thank you for your response, it is very useful for me! I realize a lot. when I read the book "iOS CoreAnimation Advanced Techniques", there are something confusing me that is :

  • image1 show the author's interpretation of this code is the same as yours.
self.layerView.contentsCenter = CGRectMake(0.25, 0.25, 0.5, 0.5);

image3

  • if the contentsCenter changed as follow:
self.layerView.contentsCenter = CGRectMake(0.25, 0.25, 0.8, 0.8);

it will display like this what confusing me mostly...

image4

  • "A bit, like 1 pixel (width) " in Horizontal. why is Horizontal(1 pixel) different from Vertical(0 pixel)?

  • how can i implement the two kind of effects like image5?

image5


Solution

  • Code:

    let image = UIImage(named: "origin")
    contentsView.contentMode = .scaleAspectFit
    contentsView.layer.contents = image?.cgImage
    contentsView.layer.contentsCenter = CGRect(x: 0.25, y: 0.25, width: 0.5, height: 0.5);
    

    enter image description here

    It's expected and it depends on two things:

    • how big is the image itself,
    • how big is the view/layer.

    Color overlays:

    • Green - this part of the image is not stretched
    • Red - this part of the image is stretched vertically, but not horizontally
    • Blue - this part of the image is stretched horizontally, but not vertically
    • Yellow - this part of the image is stretched horizontally & vertically

    What stretched means? It can be stretched into a bigger image or a smaller image. A smaller image means that it can even be zero width/height.

    Compare these two screenshots:

    enter image description here

    • On the left - it's your original image
    • On the right - it's your original image with added color overlays

    What happened?

    • You asked not to stretch the green parts
    • Vertical
      • Is there a room for the red & yellow parts?
      • Nah, not drawn, basically stretched to 0 height
    • Horizontal
      • Is there a room for the blue & yellow parts?
      • A bit, like 1 pixel (width)
      • Stretch it to 1 pixel and draw it

    Update:

    If the contentsCenter changed as follow:

    self.layerView.contentsCenter = CGRectMake(0.25, 0.25, 0.8, 0.8);
    

    it will display like ...

    contentsCenter documentation:

    The value in this property is set to the unit rectangle (0.0,0.0) (1.0,1.0) by default, which causes the entire image to scale in both dimensions. If you specify a rectangle that extends outside the unit rectangle, the result is undefined.

    With 0.25, 0.25, 0.8, 0.8 you're saying this:

    • top/left part - 25% width of the image, 25% height of the image
    • top/center part - 80% width of the image, 25% height of the image
    • top/right part - 25% width of the image, 25% height of the image
    • ...

    You're already outside of the unit rectangle - 25% width (t/l) + 80% width (t/c) + 25% width (t/r) = 130% width (1.3 > 1.0). The result is undefined.


    "A bit, like 1 pixel (width) " in Horizontal. why is Horizontal(1 pixel) different from Vertical(0 pixel)?

    It's a simple math. Once you draw not stretched top/left & top/right part, is there a space for top/center? No, wont be drawn. Yes, will be drawn and stretched to fit the space. Same applies for the vertical direction.

    how can i implement the two kind of effects like image5?

    • CGRectMake accepts four arguments - x, y, width, height.
    • Let's say you want to avoid stretching of all the corner parts (sizes of them do equal) and that the corner part size is 20% x 10% size of the image.
    • x = 0.2
    • y = 0.1
    • width = 1.0 - 2 * x = 1.0 - 2 * 0.2 = 0.6
    • height = 1.0 - 2 * y = 1.0 - 2 * 0.1 = 0.8
    • CGRectMake(0.2, 0.1, 0.6, 0.8)

    You can also achieve this with UIImage (search for Defining a Stretchable Image) & resizableImage(withCapInsets:resizingMode:) where you can define insets in pixels.