简体   繁体   English

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

[英]Constraint-based layout of images in a list in SwiftUI

I want to achieve the following constraint-based layout of images in a SwiftUI List :我想在SwiftUI List中实现以下基于约束的图像布局:

  • pin left/right edges of each Image to the list margins (adapts to screen size)将每个Image的左/右边缘固定到列表边距(适应屏幕尺寸)
  • dynamic height based on aspect ratio (I'd also be ok with fixed height)基于纵横比的动态高度(我也可以使用固定高度)
  • maintain image aspect ratio, and content should fill the space保持图像纵横比,内容应填满空间

在此处输入图像描述

What I have tried and doesn't work (based on 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()
        }
      }
    }
  }
}

The size I get from geo is (343, 32) on iPhone 11 Pro.我在 iPhone 11 Pro 上从geo获得的尺寸是 (343, 32)。 Width makes sense but it's not letting the cells expand beyond a height of 32 for some reason.宽度是有道理的,但由于某种原因,它不会让单元格扩展超过 32 的高度。 Any tips welcome because I'm really starting to miss auto layout constraints.欢迎任何提示,因为我真的开始怀念自动布局约束。

No need to use GeometryReader for something like this.不需要使用GeometryReader这样的事情。 For the fixed height, you can just supply a frame with height only.对于固定高度,您可以只提供一个仅具有heightframe You also don't need to create your own let aspectRatio = CGSize(width: 345, height: 120) - if you leave it nil (by default) it should be fine.您也不需要创建自己的let aspectRatio = CGSize(width: 345, height: 120) - 如果您将其保留为 nil(默认情况下)应该没问题。

Edit: Using padding instead of VStack with spacing编辑:使用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
            }
        }
    }
}

Result (with "test_image" ):结果(带有"test_image" ):

具有固定高度的图像行,图像拉伸以适应容器,同时保持纵横比

However, this has a fixed height of 120 , so the top and bottom of the images are cropped out.但是,它的高度固定为120 ,因此图像的顶部和底部都被裁剪掉了。 To fix this, you can just avoid frame and clipped altogether.要解决此问题,您可以完全避免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
            }
        }
    }
}

Result:结果:

具有动态高度的图像行,图像在保持纵横比的同时确定容器的高度

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM