SwiftUI LazyVGrid与List布局冲突问题
SwiftUI LazyVGrid与List布局冲突问题

SwiftUI LazyVGrid与List布局冲突问题

问题描述

在Swift UI中,尝试通过LazyVGrid实现图片的网格布局,但实际上显示的是列表布局:

List(savePhotos) {img in
    LazyVGrid(columns: columns) {
        ZStack {
            if let photoData = img.photo,let photo = UIImage(data: photoData) {
                Image(uiImage: photo)
                    .resizable()
                    .scaledToFill()
                    .frame(width: 80,height: 80)
                    .clipped()
            }
        }
        .cornerRadius(10)
    }
}

因为图片使用CoreData,因此通过List遍历存储的图片,再通过LazyVGrid展示 3 * 3 的布局:

@Query var savePhotos: [Photo]

let columns = [
    GridItem(.fixed(80)), // 自动根据屏幕宽度生成尽可能多的单元格,宽度最小为 80 点
    GridItem(.fixed(80)),
    GridItem(.fixed(80))
]

LazyVGrid的效果并没有实现出现。

问题原因

1、List 的限制

SwiftUI 的 List 是为垂直滚动设计的,它将其子视图(包括 LazyVGrid)布局为一个列表项。即使定义了网格列,它仍会按照列表项来布局。

2、网格没有单独的容器

LazyVGrid 应该直接放在一个适当的容器(如 ScrollView 或 VStack)中,而不是嵌套在 List 中。

解决方法

1、使用 ScrollView 替代 List

ScrollView 支持任意方向的滚动,适合用来承载 LazyVGrid。

ScrollView {
    LazyVGrid(columns: columns, spacing: 10) {
        ForEach(savePhotos) { img in
            if let photoData = img.photo, let photo = UIImage(data: photoData) {
                Image(uiImage: photo)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 80, height: 80) // 设置每张图片的大小
                    .cornerRadius(8)
            }
        }
    }
    .padding()
}

2、完全依赖网格布局

如果所有内容都是图片展示,直接用 LazyVGrid。

LazyVGrid(columns: columns, spacing: 10) {
    ForEach(savePhotos) { img in
        if let photoData = img.photo, let photo = UIImage(data: photoData) {
            Image(uiImage: photo)
                .resizable()
                .scaledToFill()
                .frame(width: 80, height: 80)
                .clipShape(RoundedRectangle(cornerRadius: 8))
        }
    }
}
.padding()

通过LazyVGrid和ForEach配合能够实现3*3网格布局的效果。

注意事项

1、frame 限制

在 LazyVGrid 中为每个子视图设置 frame(width:height:),确保布局一致且符合列的宽度定义。

2、spacing 调整

可以为 LazyVGrid 设置 spacing 参数,定义行间和列间的间距。

3、布局适配

如果希望网格宽度自动适配屏幕,可以用 .adaptive 替代 .fixed。

let columns = [GridItem(.adaptive(minimum: 80))]

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注