Position, Move and Stretch a UIView with contentMode

Predict what will happen when bounds change

Image for post
Image for post
Photo by Tiago Felipe Ferreira on Unsplash

I drew a circle using a UIBezierPath in a custom UIView. No problem — except on rotation the circle turned into an oval — less cool.

The solution involved no code at all. You simply set the contentMode to .redraw and.. Solved! Solution from the Storyboard:

Image for post
Image for post

But wait. There are 13 different options here. What are they, and what do they do? That’s what this article is about!

Prerequisites:

The example project

We can place a man in an UIImageView using AutoLayout constraints. You’ll also need to have an image called man nestled inside your Asset catalog.

Something like the following:

Image for post
Image for post

Now within the viewDidLoad() function of your view controller you can place some code to initialize the UIImageView and the image.

Image for post
Image for post
UIImageView
Image for post
Image for post

Which will present the man on the screen (when the App is run)

Image for post
Image for post

Which is…not ideal. So what’s going on?

The answer is in the commented out piece of code in the view controller.

// programaticView.contentMode = .scaleToFill

scaleToFill contentMode is actually the default (so it doesn’t matter if we uncomment this line or not in practice.

.scaleToFill stretches the view to fill the available space without maintaining the aspect ratio, and this means that our image looks awful.

Because the image in question has been set to the UIImageView with the height and width anchors as described above are larger than the image that we have elected to use (the man is 128x128).

There are some situations where you’d want this — perhaps you always want the image to be a certain size whether that means stretching it or not.

Scaling the view

For each of these screen shots I’ve changed the orientation of the simulator, simply to make this easier to see the image. With that said, let’s go:

.scaleToFill

Image for post
Image for post

We have already seen the default, .scaleToFill does not respect the aspect ratio.

.scaleAspectFit

This scales the image to fit the view, maintaining the aspect ratio but no section of the image is cropped. This means that there are elements of the view the remain transparent.

Image for post
Image for post

.scaleAspectFill

Maintain the aspect ratio of the content, and some of the image can be clipped.

Image for post
Image for post

But wait — we can see that this image hasn’t been clipped. It isn’t repecting the bounds of the image. We can make it do so by setting .clipsToBounds to be true, which would be programaticView.clipsToBounds = true in the view controller above.

Image for post
Image for post

Positioning the view

We can position the view by making the .contentView be either .center, .left, .right, .topRight, .topLeft, .bottomRight, .bottomLeft. These act pretty much as how you might expect.

Image for post
Image for post
.center
Image for post
Image for post
.left
Image for post
Image for post
.right
Image for post
Image for post
.topLeft
Image for post
Image for post
.top
Image for post
Image for post
.topRight
Image for post
Image for post
.bottom
Image for post
Image for post
.bottomLeft
Image for post
Image for post
.bottomRight

We can see that the image of the man is not stretched.

.redraw

This is back where the article began. The redraw method redraws the view when the bounds are changed (this happens when setNeedsDisplay() is invoked, and on orientation change).

Image for post
Image for post

This seems to be the same as .scaleToFill on the surface. But that brings us back to the initial part of the problem — drawing your own image.

The solution here would be .redraw which is back to the beginning of the article.

Conclusion

It might do you well to recognize that these options are Enumeration Cases rather than simple properties, although in practice (and the examples shown above) there is little difference. Apple have covered contentMode (without the example) which would show you the differences — without the examples shown above.

I hope this article has been of help to you, and if you have any questions or queries I’d love hear from you!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store