I am working on shipping my first visionOS app to the App Store! It is a music app, and as soon as I realised that Apple Music released two new stations, namely Love and Heartbreak, I decided to make my app, Fusion, support them.
Fixed Sized Images
I started working on a detail view and was using static artwork sizes of 500 x 500 for the given station artwork:
ArtworkImage(artwork, width: 500, height: 500)
.scaledToFit()
.cornerRadius(24)

But then I realised that if I resized the window, the image would distort when zoomed in, and neither would increase/decrease relative to the window.

As you can see in the above screenshot, I made the window bigger, but the image remains small.

I made the window smaller in this screenshot, but the image remains large.
Relative Sized Images
I needed to find a way to resize the image with the window, so I turned to GeometryReader
from SwiftUI as usual. However, I admit that GeometryReader
has always been a bit of a nightmare for me to work with. My past experiences with it still haunt me, and I dreaded the thought of trying to use it again.
I remembered the new modifier in iOS 17+ containerRelativeFrame(_:alignment:)
that I could use to resize the image with the window. And to my surprise, I discovered that visionOS 1.0 supports it too! I went back to watch the video I referred to on this modifier and started exploring it.
I decided to give it a try. I took the minimum of the maximum width and height possible for the artwork and then used AsyncImage
to make it resizable with an aspect ratio of 1 to maintain it while resizing. I then used containerRelativeFrame
to align the image horizontally, taking up 40% of the total width of the window. This made the image look great and fit perfectly in the detail view.
Here is what the code looks like:
AsyncImage(url: artwork.url(width: min(artwork.maximumWidth, artwork.maximumHeight), height: min(artwork.maximumWidth, artwork.maximumHeight))) { phase in
switch phase {
case .success(let image):
image
.resizable()
.aspectRatio(1.0, contentMode: .fit)
.cornerRadius(24)
.containerRelativeFrame(.horizontal, { length, _ in
length * 0.4
})
default:
ProgressView()
}
}

And the result? The images now get bigger with the window and smaller with the window.


I hope this helps you with your visionOS projects! Happy coding!