🐕

【SwiftUI】ContentModeにfillが設定されたImageを正方形にトリミングする

に公開

正方形にトリミングされたImageの幅と高さは、基本的に親ビューから提案サイズの小さい方となります。

理想サイズが使用されるシチュエーションとしては、上下左右のスクロールに対応したScrollViewぐらいだと思います。

Image(uiImage: uiImage)
    .resizable()
    .scaledToFill()
    .frame(minWidth: 0, idealWidth: 100, minHeight: 0, idealHeight: 100) // 重要
    .aspectRatio(1, contentMode: .fit)
    .clipped()
サンプル
struct ContentView: View {
    @State private var uiImage: UIImage? = nil
    @State private var index = 0
    
    var body: some View {
        Group {
            if let uiImage {
                content(uiImage)
            } else {
                ProgressView()
            }
        }
        .task {
            guard let url = URL(string: "https://picsum.photos/1920/1080") else { return print(1) }
            guard let data = try? await URLSession.shared.data(from: url).0 else { return print(2) }
            guard let uiImage = UIImage(data: data) else { return print(3) }
            self.uiImage = uiImage
        }
    }
    
    func image(_ uiImage: UIImage) -> some View {
        Image(uiImage: uiImage)
            .resizable()
            .scaledToFill()
            .frame(minWidth: 0, idealWidth: 100, minHeight: 0, idealHeight: 100)
            .aspectRatio(1, contentMode: .fit)
            .clipped()
    }
    
    func content(_ uiImage: UIImage) -> some View {
        VStack {
            Group {
                switch index {
                case 0: verticalStack(uiImage)
                case 1: horizontalStack(uiImage)
                case 2: verticalScrollView(uiImage)
                case 3: horizontalScrollView(uiImage)
                case 4: twoAxisScrollView(uiImage)
                default: EmptyView()
                }
            }
            .border(.primary)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .safeAreaInset(edge: .bottom) {
            Button("Next") {
                index = (index + 1) % 5
            }
        }
    }
    
    func verticalStack(_ uiImage: UIImage) -> some View {
        VStack {
            image(uiImage)
        }
        .frame(width: 300, height: 500)
    }
    
    func horizontalStack(_ uiImage: UIImage) -> some View {
        HStack {
            image(uiImage)
        }
        .frame(width: 350, height: 200)
    }
    
    func verticalScrollView(_ uiImage: UIImage) -> some View {
        ScrollView(.vertical) {
            image(uiImage)
        }
        .frame(width: 300, height: 500)
    }
    
    func horizontalScrollView(_ uiImage: UIImage) -> some View {
        ScrollView(.horizontal) {
            image(uiImage)
        }
        .frame(width: 350, height: 200)
    }
    
    func twoAxisScrollView(_ uiImage: UIImage) -> some View {
        ScrollView([.horizontal, .vertical]) {
            image(uiImage)
        }
        .frame(width: 350, height: 200)
    }
}

Discussion