在 SwiftUI 中将图像裁剪为正方形

iCo*_*eak 13 ios swiftui

我试图将多个单元格彼此相邻放置,其中每个单元格由下面的图像和文本组成。单元格本身应该是一个正方形,并且应该缩放图像以填充剩余空间(剪切图像的一部分)。

首先,我尝试将图像和下面的文字制作成正方形。现在我的问题是,我不知道如何在 SwiftUI 中正确实现。使用此代码时,我可以让它工作:

VStack {
    Image(uiImage: recipe.image!)
        .resizable()
        .aspectRatio(contentMode: .fill)
        .frame(width: 200, height: 200, alignment: .center)
        .clipped()
    Text(recipe.name)
}
Run Code Online (Sandbox Code Playgroud)

图 1 问题是,我必须指定一个固定的帧大小。我想要的是一种制作单元格的方法,它保持 1:1 的纵横比并且可以调整大小,因此我可以将它们的动态数量放在彼此相邻的屏幕上。

我也尝试使用

VStack {
    Image(uiImage: recipe.image!)
        .resizable()
        .aspectRatio(1.0, contentMode: .fit)
        .clipped()
    Text(recipe.name)
}
Run Code Online (Sandbox Code Playgroud)

图 2 这给了我方形图像,动态缩放。但问题是,图像现在被拉伸以填充正方形而不是缩放以填充它。

我的下一个想法是把它剪成方形。为此,我首先尝试将其剪成圆形(因为显然没有方形):

VStack {
    Image(uiImage: recipe.image!)
        .resizable()
        .aspectRatio(1.0, contentMode: .fit)
        .clipped()
    Text(recipe.name)
}
Run Code Online (Sandbox Code Playgroud)

图 3

但是出于某种奇怪的原因,它并没有真正剪辑图像,而是保留了剩余的空间......

那么我是不是没有看到任何东西,或者是将图像裁剪成框架修改器的唯一选项?

编辑

澄清:我不太关心文本,因为整个单元格(或者图像更简单)是方形的,无需通过.frame非方形原始图像指定其大小,也无需拉伸非方形原始图像以使其成为合身。

所以完美的解决方案是 VStack 是方形的,但获得方形图像也可以。它应该看起来像图像 1,但不必使用.frame修饰符。

eth*_*ooo 22

ZStack 将通过允许我们分层视图而不影响另一个布局来帮助解决这个问题。

对于文本:

.frame(minWidth: 0, maxWidth: .infinity) 将文本水平扩展到其父级的大小

.frame(minHeight: 0, maxHeight: .infinity) 在其他情况下很有用

至于图像:

.aspectRatio(contentMode: .fill) 使图像保持其纵横比而不是压缩到其框架的大小。

.layoutPriority(-1)降低布局图像的优先级以防止其扩展其父级(在我们的情况下为ZStackForEach)。

的值layoutPriority只需要低于默认设置为 0 的父视图。我们必须这样做,因为 SwiftUI 会在其父级之前布局子级,并且父级必须处理子级大小,除非我们手动设置不同的优先级。

.clipped()改性剂使用的边界框以掩蔽视图所以你需要将其设置为剪辑尚未1的任何图像:1分的纵横比。

    var body: some View {
        HStack {
            ForEach(0..<3, id: \.self) { index in
                ZStack {
                    Image(systemName: "doc.plaintext")
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .layoutPriority(-1)
                    VStack {
                        Spacer()
                        Text("yes")
                            .frame(minWidth: 0, maxWidth: .infinity)
                            .background(Color.white)
                    }
                }
                .clipped()
                .aspectRatio(1, contentMode: .fit)
                .border(Color.red)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑:虽然几何阅读器非常有用,但我认为应该尽可能避免使用它们。让 SwiftUI 来完成工作更干净。这是我最初的解决方案,Geometry Reader它也同样有效。

        HStack {
            ForEach(0..<3, id: \.self) { index in
                ZStack {
                    GeometryReader { proxy in
                        Image(systemName: "pencil")
                            .resizable()
                            .scaledToFill()
                            .frame(width: proxy.size.width)
                        VStack {
                            Spacer()
                            Text("yes")
                                .frame(width: proxy.size.width)
                                .background(Color.white)
                        }
                    }
                }
                .clipped()
                .aspectRatio(1, contentMode: .fit)
                .border(Color.red)
            }
        }

Run Code Online (Sandbox Code Playgroud)

  • layoutPriority(-1) 成功了。非常感谢你:你为我节省了很多时间和精力。 (2认同)

ram*_*nok 19

这是我在Reddit上找到的另一个解决方案并进行了一些改进:

Color.clear
    .aspectRatio(1, contentMode: .fit)
    .overlay(
        Image(imageName)
            .resizable()
            .scaledToFill()
        )
    .clipShape(Rectangle())
Run Code Online (Sandbox Code Playgroud)

它与 Chads 的答案类似,但不同之处在于相对于清晰颜色(背景与覆盖)放置图像的方式

奖励:让它具有圆形形状只需用作.clipShape(Circle())最后一个修饰符。其他一切保持不变