12

Replicate 12 UIKit's contentMode options in SwiftUI

 4 years ago
source link: https://sarunw.com/posts/uikits-contentmode-in-swiftui/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Replicate 12 UIKit's contentMode options in SwiftUI

12 Apr 2021 ⋅ 4 min read ⋅ SwiftUI Image Resize

Table of Contents

There are twelve way[1] to transform image in UIImageView with content mode, but we got only two content mode in SwiftUI. But, we can replicate most of them with a combination of two modifier aspectRatio(_:contentMode:) and frame(width:height:alignment:).

This is the list of UIKit's contentMode. You can visit my previous post to see what these property are.

Throughout this post, I will use two images, a big image with a size of 240x300[2] and a smaller image with a size of 80x100. You will see how each image reacts to the same content mode.

large image (240x300)large image (240x300)small image (80x100)small image (80x100)

I will put them side-by-side in image views of size 200x200. I also add a pink border for you to visualize the behavior easily. Here is our testing code.

struct ContentView: View {
var body: some View {
HStack(spacing: 200) {
Image("contentmode-large")
.resizable()
.frame(width: 200, height: 200)
.border(Color.pink)
Image("contentmode-small")
.resizable()
.frame(width: 200, height: 200)
.border(Color.pink)
}
}
}

In the examples below, I will only code for the large image for brevity.

Scaling

scaleToFill

scaleToFill scales the content to fill the view's bounds without maintaining the aspect ratio. We can do this in SwiftUI with .resizable() modifier.

Image("contentmode-large")
.resizable()
.frame(width: 200, height: 200)
.border(Color.pink)
scaleToFillscaleToFill

scaleAspectFit

scaleAspectFit scales the content to fit within the view's bounds and maintaining the aspect ratio. This might leave an empty space on one axis. We do this in SwiftUI with resizable() and .aspectRatio(contentMode: .fit) (or .scaledToFit()).

Image("contentmode-large")
.resizable()
.aspectRatio(contentMode: .fit) // 1
.frame(width: 200, height: 200)
.border(Color.pink)
Image("contentmode-small")
.resizable()
.scaledToFit() // 2
.frame(width: 200, height: 200)
.border(Color.pink)

You can use .aspectRatio(contentMode: .fit) <1> or shorthand version, .scaledToFit() <2>.

scaleAspectFitscaleAspectFit

scaleAspectFill

scaleAspectFill scales the content to fill the view's bounds and maintaining the aspect ratio. This might cause some portion of the image to extend beyond the view's bounds. We do this in SwiftUI with resizable() and .aspectRatio(contentMode: .fill) (or .scaledToFill()).

Image("contentmode-large")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.border(Color.pink)
Image("contentmode-small")
.resizable()
.scaledToFill()
.frame(width: 200, height: 200)
.border(Color.pink)
scaleAspectFillscaleAspectFill mobileatscale.png

Positioning

We have nine mode to position an image. Each mode will pin the image to the respective position without scaling the image. For example, center will pin the content's center to the view's center, top will pin the content's top to the view's top.

Since we don't need to scale the image, we don't need .resizable() and .aspectRatio() here. We can rely on alignment parameter of .frame(width:height:alignment:).

center

Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .center)
.border(Color.pink)
centercenter
Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .top)
.border(Color.pink)
toptop

bottom

Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .bottom)
.border(Color.pink)
bottombottom
Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .leading)
.border(Color.pink)
leftleft

right

Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .trailing)
.border(Color.pink)
rightright

topLeft

Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .topLeading)
.border(Color.pink)
topLefttopLeft

topRight

Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .topTrailing)
.border(Color.pink)
topRighttopRight

bottomLeft

Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .bottomLeading)
.border(Color.pink)
bottomLeftbottomLeft

bottomRight

Image("contentmode-large")
.frame(width: 200, height: 200, alignment: .bottomTrailing)
.border(Color.pink)
bottomRightbottomRight

As you can see, the only difference here is we use leading instead of left and trailing instead of right.


  1. I didn't put .redraw into consideration here since it is not modify position or size of an image. More detail here ↩︎

  2. Photo by Mae Mu on Unsplash ↩︎


Read more article about SwiftUI, Image, Resize,

or see all available topic

Get new posts weekly

If you enjoy this article, you can subscribe to the weekly newsletter.

Every Friday, you’ll get a quick recap of all articles and tips posted on this site — entirely for free.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron

Tweet

Share

Previous
How to add background to your view in SwiftUI

Learn how hard or easy it is to add a background view in SwiftUI.

Next
How to resize an image view to fit a container view in SwiftUI

Learn how to fit an image view to any container.

← Home


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK