SwiftUI 列表中基于约束的图像布局

Posted

技术标签:

【中文标题】SwiftUI 列表中基于约束的图像布局【英文标题】:Constraint-based layout of images in a list in SwiftUI 【发布时间】:2021-06-03 16:32:24 【问题描述】:

我想在SwiftUI List 中实现以下基于约束的图像布局:

将每个Image 的左/右边缘固定到列表边距(适应屏幕大小) 基于纵横比的动态高度(我也可以使用固定高度) 保持图片纵横比,内容应填满空间

我尝试过但不起作用的方法(基于this article):

struct MyView: View 
  @ObservedObject var viewModel: MyViewModel
  let aspectRatio = CGSize(width: 345, height: 120)

  var body: some View 
    List 
      ForEach(viewModel.items)  item in
        GeometryReader  geo in
          Image("test_image")
            .resizable()
            .aspectRatio(aspectRatio, contentMode: .fill)
            .frame(width: geo.size.width)
            .clipped()
        
      
    
  

我从geo 得到的尺寸在 iPhone 11 Pro 上是 (343, 32)。宽度是有道理的,但由于某种原因,它不会让单元格扩展超过 32 的高度。欢迎任何提示,因为我真的开始怀念自动布局约束了。

【问题讨论】:

【参考方案1】:

不需要使用GeometryReader 来处理这样的事情。对于固定高度,您只能提供 frameheight。您也不需要创建自己的 let aspectRatio = CGSize(width: 345, height: 120) - 如果您将其保留为 nil(默认情况下)应该没问题。

编辑:使用 padding 而不是 VStack 带间距

struct MyView: View 
    var body: some View 
        List 
            ForEach(0..<10, id: \.self)  item in
                Image("test_image")
                    .resizable()
                    .aspectRatio(contentMode: .fill) /// no need for custom aspect ratio
                    .frame(height: 120) /// fixed height of image
                    .clipped() /// stop image from overflowing
                    .padding(.vertical, 12) /// extra vertical padding
            
        
    

结果("test_image"):


但是,它的高度固定为120,因此图像的顶部和底部都被裁剪掉了。要解决此问题,您可以完全避免使用 frameclipped

struct MyView: View 
    var body: some View 
        List 
            ForEach(0..<10, id: \.self)  item in
                Image("test_image")
                    .resizable()
                    .aspectRatio(contentMode: .fill) /// doesn't matter if it's fit or fill
                    .padding(.vertical, 12) /// extra vertical padding
            
        
    

结果:

【讨论】:

为什么会有VStack List?不应该是要么吗?不过谢谢你,这让我走上了正轨。不回答动态高度问题,但在这一点上这将是一个奖励。 @rmp251 你是对的,它应该是ListVStack + ScrollView。我只为间距做了 VStack - 我会更新我的答案。 当图像相对于固定高度非常宽时,此解决方案似乎会中断。它不允许宽度受边距限制。但是它适用于“高”图像(例如正方形)。

以上是关于SwiftUI 列表中基于约束的图像布局的主要内容,如果未能解决你的问题,请参考以下文章

Swift:将 SwiftUI 元素添加到 UIKit 项目:无法正确应用约束

如何使用 SwiftUI 将图像对齐到列表行的右上角?

自动布局,异步加载图像到 uiimageview (Swift, xCode6)

iOS:如何在 SwiftUI 页面顶部制作我的图像徽标

自动布局约束如何与 SwiftUI 框架一起使用 [重复]

AutoLayout - 保持图像与水平约束的比例(Swift Xcode 6)