概要
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を使用する必要があります。
以下、サンプルコードと表示される画面です。
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 |
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を表示させる事ができるので是非お試しください!