在 SwiftUI 中将图像裁剪为正方形 [英] Clip image to square in SwiftUI

查看:31
本文介绍了在 SwiftUI 中将图像裁剪为正方形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to put multiple cells next to each other where each cell consists of an image and a text below. The cell itself should be a square and the image should be scaled to fill the remaining space (cutting a part of the image).

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

First I tried just making the image square and the text below. Now my problem is, that I don't know how to properly achieve that in SwiftUI. I can get it to work, when using this code:

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

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

The problem is, that I have to specify a fixed frame size. What I want is a way to make a cell, that keeps an aspect ratio of 1:1 and is resizable, so I can fit a dynamic amount of them on a screen next to each other.

我也试过使用

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

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

which gives me square images, that scale dynamically. But the problem is, that the image now gets stretched to fill the square and not scaled to fill it.

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

My next idea was to clip it to a square shape. For that I first tried to clip it into a circle shape (because apparently there is not square shape):

VStack {
    Image(uiImage: recipe.image!)
        .resizable()
        .aspectRatio(contentMode: .fit)
        .clipShape(Circle())
    Text(recipe.name)
}

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

But for some odd reason, it didn't really clip the image but instead kept the remaining space...

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

So am I not seeing something or is the only option to clip an image square the frame modifier?

澄清:我不太关心文本,因为整个单元格(或者图像更简单)是方形的,而不必通过 .frame 和没有拉伸非方形原始图像以使其适合.

To clarify: I don't care about the text as much, as about the whole cell (or if it's simpler the image) being square, without having to specify its size via .frame and without the non-square original image being stretched to make it fit.

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

So the perfect solution would be that the VStack is square but getting a square image would also be okay. It should look like Image 1, but without having to use the .frame modifier.

推荐答案

ZStack 将帮助我们解决这个问题,它允许我们对视图进行分层,而不会影响另一个视图的布局.

A ZStack will help solve this by allowing us to layer views without one effecting the layout of the other.

对于文本:

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

.frame(minWidth: 0, maxWidth: .infinity) to expand the text horizontally to its parent's size

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

至于图片:

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

.aspectRatio(contentMode: .fill) to make the image maintain its aspect ratio rather than squashing to the size of its frame.

.layoutPriority(-1) 降低布局图像的优先级以防止其扩展其父级(ForEach 中的 ZStack> 在我们的例子中).

.layoutPriority(-1) to de-prioritize laying out the image to prevent it from expanding its parent (the ZStack within the ForEach in our case).

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

The value for layoutPriority just needs to be lower than the parent views which will be set to 0 by default. We have to do this because SwiftUI will layout a child before its parent, and the parent has to deal with the child size unless we manually prioritize differently.

.clipped()修改器使用边界框来屏蔽视图,因此您需要将其设置为剪裁任何不是 1:1 纵横比的图像.

The .clipped() modifier uses the bounding frame to mask the view so you'll need to set it to clip any images that aren't already 1:1 aspect ratio.

    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)
            }
        }
    }

虽然几何阅读器非常有用,但我认为应尽可能避免使用它们.让 SwiftUI 完成工作更干净.这是我使用 Geometry Reader 的初始解决方案效果一样好.

While geometry readers are super useful I think they should be avoided whenever possible. It's cleaner to let SwiftUI do the work. This is my initial solution with a Geometry Reader that works just as well.

        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)
            }
        }

这篇关于在 SwiftUI 中将图像裁剪为正方形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆