如何将图像剪辑到惰性网格内的正方形? (斯威夫特用户界面)

Posted

技术标签:

【中文标题】如何将图像剪辑到惰性网格内的正方形? (斯威夫特用户界面)【英文标题】:How do you clip an image to a square inside a lazy grid? (SwiftUI) 【发布时间】:2020-07-08 09:40:30 【问题描述】:

这不是 this question 的副本。

您将在下面看到一个包含 3 列的矩形网格。我正在尝试使用图像来达到相同的效果。图像应被剪裁,否则不会显得拉伸或扭曲。

这是我实现矩形网格的方法...

// In my view struct...

private let threeColumnGrid = [
    GridItem(.flexible(minimum: 40)),
    GridItem(.flexible(minimum: 40)),
    GridItem(.flexible(minimum: 40)),
]

// In my body...

LazyVGrid(columns: threeColumnGrid, alignment: .center) 
    ForEach(model.imageNames, id: \.self)  imageName in
        Rectangle()
            .foregroundColor(.red)
            .aspectRatio(1, contentMode: .fit)
    

这是我想要使用矩形的布局...

这是我的目标……

更新:

如果我这样做......

Image(item)
    .resizable()
    .aspectRatio(1, contentMode: .fit)

如果图像的纵横比不是 1:1,则图像会失真。例如,下面屏幕截图中的圆形图像应该是一个完美的圆形。

【问题讨论】:

图像有自己的尺寸,但形状(在本例中为矩形)没有,因此布局可能不同(输入参数相同)。你会以某种方式展示你期望从图像中得到什么吗? 我已经用我想要的示例更新了我的问题。 【参考方案1】:

我找到了解决办法。

定义列数...

// Somewhere in my view struct
private let threeColumnGrid = [
    GridItem(.flexible(minimum: 40)),
    GridItem(.flexible(minimum: 40)),
    GridItem(.flexible(minimum: 40)),
]

创建网格...

LazyVGrid(columns: threeColumnGrid, alignment: .center) 
    ForEach(model.imageNames, id: \.self)  item in
        GeometryReader  gr in
            Image(item)
                .resizable()
                .scaledToFill()
                .frame(height: gr.size.width)
        
        .clipped()
        .aspectRatio(1, contentMode: .fit)
    

【讨论】:

这为我解决了同样的问题,但将框架修饰符更改为 .frame(height: gr.size.width) 以便我的图像始终具有相同的宽度和高度。我很好奇在这里将框架的宽度设置为几何体的建议宽度有什么作用。 是我还是这不是图像在正方形中间的中心? 试试这个框架修饰符:frame(height: gr.size.width, alignment: .center)【参考方案2】:

我发现 DPMitu 的答案没有使图像居中(它与前缘对齐)。

这对我来说效果更好(也不需要 GeometryReader):

  LazyVGrid(columns: columns, spacing: 30) 
       ForEach(items)  item in
           Image("IMG_0044")
               .resizable()
               .scaledToFill()
               .frame(minWidth: 0, maxWidth: .infinity)
               .aspectRatio(1, contentMode: .fill)
               .clipped() //Alternatively you can use cornerRadius for the same effect
               //.cornerRadius(10)
       
  
    

我在这里找到它https://www.appcoda.com/learnswiftui/swiftui-gridlayout.html 大约在页面的一半

【讨论】:

这似乎无法实现肖像图像的方形效果... 要实现与肖像图像相同的效果,请将 .frame() 行更改为 .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)。只要父视图的框架是方形的,它就应该以这种方式与横向和纵向一起使用。 拯救了我的一天,谢谢【参考方案3】:

有些人询问图像是否偏离中心。您可以通过添加.position(x: gr.frame(in: .local).midX, y: gr.frame(in: .local).midY) 来调整它。所以完整的事情是:

列数

// Somewhere in my view struct
private let threeColumnGrid = [
    GridItem(.flexible(minimum: 40)),
    GridItem(.flexible(minimum: 40)),
    GridItem(.flexible(minimum: 40)),
]

创建网格

LazyVGrid(columns: threeColumnGrid, alignment: .center) 
    ForEach(model.imageNames, id: \.self)  item in
        GeometryReader  gr in
            Image(item)
                .resizable()
                .scaledToFill()
                .frame(height: gr.size.width)
                .position(x: gr.frame(in: .local).midX, y: gr.frame(in: .local).midY)
        
        .clipped()
        .aspectRatio(1, contentMode: .fit)
    

【讨论】:

【参考方案4】:

没有GeometryReader 的解决方案和正确缩放的图像。

struct ContentView: View 

    private let columns = [
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
    ]

    private let imageNames = ["image0", "image1", "image2", "image3", "image4"];

    var body: some View 
        LazyVGrid(columns: columns, content: 
            ForEach(imageNames, id: \.self)  name in
                Color.clear
                    .background(Image(name)
                                    .resizable()
                                    .scaledToFill()
                    )
                    .aspectRatio(1, contentMode: .fill)
                    .clipped()
                    .contentShape(Rectangle()) // <-- this is important to fix gesture recognition
            
        )
    

【讨论】:

【参考方案5】:

我用一些随机图像复制了一些代码并得到了以下内容。但不确定您的目标,但希望对您有所帮助

使用 Xcode 12 / ios 14 测试

struct TestImagesInGrid: View 
    @State private var imageNames: [String]

    private let threeColumnGrid = [
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
    ]

    init() 
        _imageNames = State(initialValue: (0..<8).map  _ in
            "image_\(Int.random(in: 1...3))"
        )
    

    var body: some View 
        LazyVGrid(columns: threeColumnGrid, alignment: .center) 
            ForEach(imageNames.indices)  i in
                Image(imageNames[i]).resizable()
                    .aspectRatio(1, contentMode: .fit)
            
        
    

【讨论】:

我已经使用您的技术更新了我的问题。这仅适用于图像的纵横比已经为 1:1 的情况。【参考方案6】:

我遇到了类似的问题,我就是这样解决的。

GeometryReader  geo in
    Image(item)
        .resizable()
        .aspectRatio(contentMode: .fill)
        .clipShape(
            Rectangle()
                .size(width: geo.size.width, height: geo.size.width)
        )

【讨论】:

【参考方案7】:

我使用 Rectangle 来实现帮助,就在下面

LazyVGrid(columns: [.init(.adaptive(minimum: 88, maximum: 128), spacing: 2)], spacing: 2) 
    ForEach(urls, id: \.self)  url in
        Rectangle()
            .aspectRatio(1, contentMode: .fit)
            .foregroundColor(.clear)
            .overlay 
                GeometryReader  geometry in
                    if let image = UIImage(contentsOfFile: url.relativePath) 
                        Image(uiImage: image)
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                            .frame(width: geometry.size.width, height: geometry.size.height, alignment: .center)
                            .clipped()
                    
                
            
    

【讨论】:

以上是关于如何将图像剪辑到惰性网格内的正方形? (斯威夫特用户界面)的主要内容,如果未能解决你的问题,请参考以下文章

如何使网格内的图像控件居中?

如何剪辑图像或剪切不需要的部分?

响应式正方形网格内的响应式正方形网格

显示表格内的图像时出错!斯威夫特 3

如何在响应式方形网格中仅使背景图像透明?

蒙太奇3图像在2x2网格中,首先在顶部中心(如“triforce”)?