问题
I have a list of profile images (of various sizes) that I want each one to downsize to fit into its view, but I don't want them to be upsized and be pixilated. Instead, I want small images to stay at the resolution they are at. How do I can achieve this?
This is what I've been using so far (but it resizes up):
VStack {
Image(...)
.resizable()
.scaledToFill()
}.frame(width:200, height:200)
回答1:
I did not find simple solution in API either, so here is a placeholder that looks appropriate for me. It is a bit complicated by works.
Tested with Xcode 11.2+ / iOS 13.2+.

Demo of usage:
struct DemoImagePlaceholder_Previews: PreviewProvider {
static var previews: some View {
VStack {
ImagePlaceholder(image: Image("icon"), size: CGSize(width: 200, height: 200))
.border(Color.red)
ImagePlaceholder(image: Image("large_image"), size: CGSize(width: 200, height: 200))
.border(Color.red)
}
}
}
Solution:
struct OriginalImageRect {
var rect: Anchor<CGRect>? = nil
}
struct OriginalImageRectKey: PreferenceKey {
static var defaultValue: OriginalImageRect = OriginalImageRect()
static func reduce(value: inout OriginalImageRect, nextValue: () -> OriginalImageRect) {
value = nextValue()
}
}
struct ImagePlaceholder: View {
let image: Image
let size: CGSize
var body: some View {
VStack {
self.image.opacity(0)
.anchorPreference(key: OriginalImageRectKey.self, value: .bounds) {
OriginalImageRect(rect: $0)
}
}
.frame(width: size.width, height: size.height)
.overlayPreferenceValue(OriginalImageRectKey.self) { pref in
GeometryReader { gp -> Image in
if pref.rect != nil, CGRect(origin: .zero, size: gp.size).contains(gp[pref.rect!]) {
return self.image
} else {
return self.image.resizable() // .fill by default, otherwise needs to wrap in AnyView
}
}
}
}
}
来源:https://stackoverflow.com/questions/60806362/downsize-but-not-upsize-a-swiftui-image