NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

【SwiftUI】Imageのサイズを変更する方法

概要

SwiftUIでImageのサイズを変更する際にframeでwidth及びheightを指定するだけでは変更できません。resizableと言うmodifierを付与する事でframeで指定したサイズに変更する事ができます。
ただこれだけだとアスペクト比が自動的に調整されるので想定外に画面が崩れてしまうケースがあります。
そんなImageを思い通りのサイズに表現するためにどのようにすればよいのか紹介したいと思います。

環境

この記事は以下のバージョン環境のもと作成されたものです。
【Xcode】14.1
【iOS】16.1
【macOS】Monterey

前提

今回は次の2枚のImageを使用します。

sample1 sample2
縦長 横長
1920 × 3417 2400 × 1600
https://unsplash.com/ja/%E5%86%99%E7%9C%9F/sLAk1guBG90 https://unsplash.com/ja/%E5%86%99%E7%9C%9F/e4usjv5lmhE

resizableでframeサイズを反映させる

冒頭でも記述したように、SwiftUIでImageを任意のサイズで表示したい場合はresizableを使用する必要があります。

Apple Developer Documentation

以下、サンプルコードと表示される画面です。

struct ImageTestView: View {
    var body: some View {
        VStack {
            VStack(spacing: 0) {
                Text("縦長")
                Image("sample1")
                    .resizable()
                    .frame(width: 200, height: 200)
            }
            VStack(spacing: 0) {
                Text("横長")
                Image("sample2")
                    .resizable()
                    .frame(width: 200, height: 200)
            }
        }
    }
}

一見よさそうですが、frameサイズが200 × 200なのでアスペクト比が自動的に1:1に調整されています。
ではこれを3:2となるように300 × 200にしてみます。

元々が横長Imageのsample2に関しては元のアスペクト比に調整されたので違和感ないImageになっていますが、元々が縦長Imageのsample1に関しては更に元のアスペクト比から乖離した状態になっています。

スケールやアスペクト比を調整する

スケールやアスペクト比を調整するには以下のmodifierを使用します。

aspectRatio
https://developer.apple.com/documentation/swiftui/view/aspectratio(_:contentmode:)-771ow
アスペクト比は3:2で左がfil、右がfill
CGSizeで任意のアスペクト比を指定する事ができます。
ContentModeではfitかfillを指定する事でスケールの指定をする事ができます。
scaledToFit
https://developer.apple.com/documentation/swiftui/menu/scaledtofit()
CGSizeで任意のアスペクト比を指定する事ができます。
元のアスペクト比を維持しながらframe (赤枠)で指定したサイズ内に収まるようにImageをスケールさせます。
scaledToFill
https://developer.apple.com/documentation/swiftui/link/scaledtofill()
CGSizeで任意のアスペクト比を指定する事ができます。
元のアスペクト比を維持しながらframe(赤枠)で指定したサイズに合わせて最大にImageをスケールさせます。
fillを指定した場合はframeで指定したサイズより大きく表示される可能性があるので注意が必要です。

元のアスペクト比を保ちつつ、frame内に収める

上記のサンプルですと、どれもframeに対して小さくなったり、大きくなったりします。理由は指定したいサイズと元のImageのアスペクト比が異なる中で自動でスケール調整されるためです。
でもframeで指定したサイズにしたい場合もあると思いますので、その時は.clipShape(Rectangle())で指定のサイズに切り抜きします。

struct ImageTestView: View {
    var body: some View {
        VStack {
            VStack(spacing: 0) {
                Text("縦長")
                Image("sample1")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 200, height: 200)
                    .clipShape(Rectangle())
            }
            VStack(spacing: 0) {
                Text("横長")
                Image("sample2")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 200, height: 200)
                    .clipShape(Rectangle())
            }
        }
    }
}

これで元のアスペクト比を維持しつつ、指定のサイズにImageを表示させる事ができます。
ただ注意が必要なのはImageの中心にframeサイズの中心を合わせて切り抜いているため、上下や左右が切り取られてしまいます。中心位置を任意で指定したい場合は.clipShape(Rectangle())の前に.offset() で指定する事で調整する事ができます。

まとめ

SwiftUIでImageのサイズを変更する際には一手間必要で、初見でハマりやすいかなと思いましたので、resizableを付与する点からスケール、アスペクト比、更にclipShapeで任意のサイズに切り抜く方法を紹介させていただきました。
これで自由にImageを表示させる事ができるので是非お試しください!

執筆者岡優志

iOSエンジニア
iOSを専門とし、モバイルアプリの開発を行なっています。

Twitter