What type of contents UIViewContentMode mode refers to?

8.5k views Asked by At

According to the official doc on UIView about the contentMode property:

The content mode specifies how the cached bitmap of the view’s layer is adjusted when the view’s bounds change

What's defined the content in this definition? Is it a sub view or when we have define a background color for a view for example.

My very first guess was that it should apply at least for the subviews in a view, but for example the following code snippet will not give me the expected result when playing with the UIViewContentModeCenter tag:

 UIView* redView = [[UIView alloc] initWithFrame:CGRectMake(80, 80, 150, 200)];
 redView.contentMode = UIViewContentModeCenter;
 redView.backgroundColor = [UIColor redColor];

 UIView* greenView = [[UIView alloc] initWithFrame:redView.bounds];
 greenView.backgroundColor = [UIColor greenColor];
 [redView addSubview:greenView];

 redView.frame = CGRectInset(redView.frame, -5, -5);
 [self.view addSubview:redView];

I have just set up a redView that will include a greenView. I have also set-up the content mode of the redview to UIViewContentModeCenter - why in the code I wrote the greenView is not centered when I change the frame of its parent? isn't what UIViewContentModeCenter is supposed to do?

Thanks for clarifying!

Ps: You can easily test the above code in the loadView of a simple view controller template project.

2

There are 2 answers

0
nvrtd frst On BEST ANSWER

From the documentation:

The content mode specifies how the cached bitmap of the view’s layer is adjusted when the view’s bounds change.

For an image view, this is talking about the image. For a view that draws its content, this is talking about the drawn content. It does not affect the layout of subviews.

You need to look at the autoresizing masks in place on the subviews. Content mode is a red herring here. If you can't achieve the layout you need using autoresizing masks, then you need to implement layoutSubviews and calculate the subview positions and frames manually.

from jrturton's answer to: https://stackoverflow.com/a/14111480/1374512

0
Felix On

First read about Content Modes here

In your example you change the frame of the red view. That will invoke layoutSubviews on the view which will reposition the green view according to the layout constraints or autoresizing masks. You haven't specified any. So the frame of the green view will stay the same.

The content mode specifies how the view's layer should update when resizing. Depending on the content mode drawRect will be called or not.

You can test the effect of the different content modes with the following example:

Add a UIView subclass, that draws a circle using this drawRect implementation:

- (void)drawRect:(CGRect)rect
{
    // Drawing code
    NSLog(@"drawRect %@", NSStringFromCGRect(rect));

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextAddEllipseInRect(ctx, self.bounds);
    [[UIColor redColor] setFill];
    CGContextFillPath(ctx);
}

In the view controller create and add the circle view:

CircleView* circleView = [[CircleView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];
circleView.contentMode = UIViewContentModeCenter; // <- try different modes here
[self.view addSubview:circleView];

Now lets animate the frame and see what happens:

dispatch_async(dispatch_get_main_queue(), ^{
    [UIView animateWithDuration:5 animations:^{
        circleView.frame = CGRectMake(10, 10, 100, 200);
    }];
});

I'm doing that asynchronously to force CoreGraphics to draw the view at least one time with the original frame. When you don't set the content mode you end up with a blurry circle, because it just scales up without redrawing. UIViewContentModeCenter makes the small circle stay at the center - also no redraw needed. UIViewContentModeRedraw makes the view draw the view again with the new frame. Actually that happens before the animation starts.

Note that the content mode can affect the drawing performance.