https://medium.com/@wendyabrantes/swift-ui-square-image-modifier-3a4370ca561f
こちらの記事を参考に実装しました。
GeometryReader(content: { geometry in
Image(uiImage: image)
.resizable()
.scaledToFill()
.frame(width: geometry.size.width, height: geometry.size.height)
})
.aspectRatio(1, contentMode: .fit)
上記の記事との違いはGeometryReader内のImageの属性に.frame
でGeometryReaderのsizeを渡しています。Imageにframeを渡すことで、GeometryReaderの表示領域に対してscaledToFillのリサイズが当てられます。よってアスペクト比を固定しつつ中央寄せで任意のアスペクト比でクリップすることができるようになります。
この方法のメリットとして、子要素でサイズが決まるのではなくサイズは親要素側で提供された表示可能領域にあわせてリサイズするのでLazyVGridなどで使用する際などにサイズを固定化する必要がなくなります。
サンプルコード
struct ProductGridCell: View {
let name: String
let price: Int
let image: UIImage
var body: some View {
VStack(alignment: .leading, spacing: 3) {
GeometryReader(content: { geometry in
Image(uiImage: image)
.resizable()
.scaledToFill()
.frame(width: geometry.size.width, height: geometry.size.height)
})
.aspectRatio(1, contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 4))
Text(name)
.foregroundColor(.primary)
.font(.caption)
Text("¥\(price)")
.font(.caption2)
.foregroundColor(.secondary)
}
}
}
struct ProductGridCell_Previews: PreviewProvider {
static var previews: some View {
ScrollView {
LazyVGrid(columns: [GridItem(), GridItem(), GridItem()], content: {
ForEach(0..<20) { _ in
ProductGridCell(name: "どら焼き", price: 300, image: UIImage(imageLiteralResourceName: "product"))
}
})
.padding()
}
}
}