有没有办法使用几何阅读器将我的 SwiftUI 图像的宽度定义为相对于屏幕尺寸?

Posted

技术标签:

【中文标题】有没有办法使用几何阅读器将我的 SwiftUI 图像的宽度定义为相对于屏幕尺寸?【英文标题】:Is there a way to define the width of my SwiftUI Image to be relative to screen size using Geometry Reader? 【发布时间】:2020-06-13 14:32:03 【问题描述】:

我正在通过一个示例应用程序来熟悉 Swift 和 SwiftUI,并且我想结合使用自定义视图和 GeometryReader 的复合布局的想法来确定设备的屏幕大小。

我正在尝试构建的页面是一个可滚动的朋友列表,其中每个行项都是一个按钮,可以选择该按钮来展开列表以查看每个朋友的更多详细信息。我已经将按钮和所有包含视图构建为FriendView,以便在我的FriendListView 内部使用。我在FriendListView 中定义了2 个GeometryReader 视图,但不知道如何从FriendView 中定义每一行的大小以使其保持适当的大小。

对此的需求来自于并非用户稍后可以为其朋友设置的每张图片都具有相同的尺寸,因此我希望保持一致。我知道我可以设置 .frame() 修饰符并对宽度进行硬编码,但我希望它与屏幕相关,以便在所有手机屏幕上保持一致。

示例:当一行未展开时,图像应占设备宽度的一半。当它展开时,我希望它占据设备屏幕宽度的四分之一。

截图

Application View

示例代码

struct FriendListView: View 
    var pets = ["Woofer", "Floofer", "Booper"]

    var body: some View 
        GeometryReader  geo1 in
            NavigationView 
                GeometryReader  geo2 in
                    List(self.pets, id: \.self)  pet in
                            FriendView(name: pet)

                    // End of List
                
                .navigationBarTitle(Text("Furiends"))

            // End of NavigationView
        // End of GeometryReader geo1
    // End of body

struct FriendView: View 
    @State private var isExpanded = false
    var randomPic = Int.random(in: 1...2)

    var name =  ""
    var breed = "Dawg"
    var body: some View 

            Button(action: self.toggleExpand) 
                HStack 
                    VStack 
                    Image("dog\(self.randomPic)")
                        .resizable()
                        .renderingMode(.original)
                        .scaledToFill()
                        .clipShape(Circle())

                       if self.isExpanded == false 
                        Text(self.name)
                            .font(.title)
                            .foregroundColor(.primary)
                       
                   

                   if self.isExpanded == true 
                       VStack 
                        Text(self.name).font(.title)
                        Text(self.breed).font(.headline)
                       
                       .foregroundColor(.primary)
                   
               
            // End of Button
    
    func toggleExpand() 
        isExpanded.toggle()
    

【问题讨论】:

【参考方案1】:

您可以在顶层FriendListView 中定义一个GeometryReader 并将屏幕宽度传递给FriendView

struct FriendListView: View 
    var pets = ["Woofer", "Floofer", "Booper"]

    var body: some View 
        GeometryReader  geo in
            NavigationView 
                List(self.pets, id: \.self)  pet in
                    FriendView(name: pet, screenWidth: geo.size.width)
                
                .navigationBarTitle(Text("Furiends"))
            
        
    

然后使用.frame 设置图像的最大宽度。

struct FriendView: View 
    ...

    var screenWidth: CGFloat

    var imageWidth: CGFloat 
        isExpanded ? screenWidth / 4 : screenWidth / 2
    

    var body: some View 
        Button(action: self.toggleExpand) 
            HStack 
                VStack 
                    Image("dog\(self.randomPic)")
                        .resizable()
                        .renderingMode(.original)
                        .scaledToFill()
                        .clipShape(Circle())
                        .frame(width: imageWidth, height: imageWidth)  // <- add frame boundaries

                    if self.isExpanded == false 
                        Text(self.name)
                            .font(.title)
                            .foregroundColor(.primary)
                    
                

                if self.isExpanded == true 
                    VStack 
                        Text(self.name).font(.title)
                        Text(self.breed).font(.headline)
                    
                    .foregroundColor(.primary)
                
            
        
    

    func toggleExpand() 
        isExpanded.toggle()
    

如果您希望图片居中,可以使用Spacer

HStack 
    Spacer()
    FriendView(name: pet, screenWidth: geo.size.width)
    Spacer()

【讨论】:

这有助于我理解如何将宽度传递到新视图中。我在框架修改器中尝试了不同的参数,包括您提供的参数,但图像仍然呈现为不同的宽度。关于我应该如何构建框架修改器的任何建议? 我不确定...我提供的示例已经过测试,它对我有用。我选择了两张图片(一张正方形和一张长方形)。在上面的视图中,两者的大小相同。您是尝试了我的整个代码还是部分代码? (我只使用了一个 GeometryReader)。 是的,我删除了额外的 GeometryReader,并认为它与 clipShape 有关。与我在原始帖子中的屏幕截图相同的行为。如果您想尝试使用这些确切的图片,我已将所有文件上传到 repo。 github.com/MichaelWDanko/furiends 是的,这是正确的。我看到圆形的细微差别。抱歉,如果我没有解释清楚。感谢帮助 太棒了!我确实必须将其更改为使用width:heightmaxWidth:maxHeight,但我终于能够排队了。我知道这是一个小调整,但感谢您的帮助。我将您的答案标记为解决此问题的答案。

以上是关于有没有办法使用几何阅读器将我的 SwiftUI 图像的宽度定义为相对于屏幕尺寸?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 将值从几何阅读器传递给函数

如何使用 SwiftUI 制作具有绝对位置的底栏

SwiftUI 动画进阶 - part2 几何效果

GeometryReader 大小计算 SwiftUI

SwiftUI:从嵌套视图调用方法

SwiftUI 中的匹配几何效果不起作用