如何在SwiftUI中创建网格

rfbsl7qr  于 2023-06-28  发布在  Swift
关注(0)|答案(5)|浏览(190)

我知道我们可以像这样在垂直SwiftUI中创建一个List,

struct ContentView : View {
    var body: some View {
        NavigationView {
            List {
                Text("Hello")
            }
        }
    }
}

但是我们有没有办法把列表分成2个或3个,或者更多的跨度,像在UICollectionView中那样覆盖屏幕

wqsoz72f

wqsoz72f1#

checkout 基于ZStack的示例here

Grid(0...100) { _ in
    Rectangle()
        .foregroundColor(.blue)
}

k7fdbhmy

k7fdbhmy2#

iOS 14

您可以使用两个新的本机View

  1. LazyHGrid

  2. LazyVGrid

使用代码或直接从库中:

该库包含一个完全工作的示例代码,您可以自己测试。

4uqofj5v

4uqofj5v3#

你可以像这样创建你的customView来实现UICollectionView行为:

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            ScrollView(showsHorizontalIndicator: true) {
                HStack {
                    ForEach(0...10) {_ in
                        GridView()
                    }
                }
            }
            List {
                ForEach(0...5) {_ in
                    ListView()
                }
            }
            Spacer()
        }
    }
}

struct ListView : View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello World!"/*@END_MENU_TOKEN@*/)
        .color(.red)
    }
}

struct GridView : View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Image("marker")
                .renderingMode(.original)
                .cornerRadius(5)
                .frame(height: 200)
                .border(Color.red)
            Text("test")
        }
    }
}

8e2ybdfx

8e2ybdfx4#

适用于Xcode 12上的iOS/iPadOS 14。您可以使用LazyVGrid将用户看到的内容加载到屏幕上,而不是整个列表,List默认为lazy。

import SwiftUI

//MARK: - Adaptive
struct ContentView: View {
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: [GridItem(.adaptive(minimum:100))]) {
                ForEach(yourObjects) { object in
                    YourObjectView(item: object)
                }
            }
        }
    }
}

//MARK: - Custom Columns
struct ContentView: View {
        
    var body: some View {
         ScrollView {   
             LazyVGrid(columns: Array(repeating: GridItem(), count: 4)) {
                 ForEach(yourObjects) { object in
                     YourObjectView(item: object)
                 }
             }
         }
    }
}

不要忘记将infoobjects替换为您的info,将YourObjectView替换为您的customView

dfddblmv

dfddblmv5#

🔴 SwiftUI的LazyVGridLazyHGrid为我们提供了相当灵活的网格布局。
最简单的网格是由三件事组成的:您的原始数据,描述您想要的布局的GridItem数组,以及将数据和布局结合在一起的LazyVGrid或LazyHGrid。
例如,这将使用大小为80点的单元格创建垂直网格布局:

struct ContentView: View {
    let data = (1...100).map { "Item \($0)" }

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

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(data, id: \.self) { item in
                    Text(item)
                }
            }
            .padding(.horizontal)
        }
        .frame(maxHeight: 300)
    }
}

🔴 使用GridItem(.adaptive(最小值:80))意味着我们希望网格每行容纳尽可能多的项目,每个项目的最小大小为80个点。
如果你想控制列的数量,你可以使用
.flexible()
,它也可以让你指定每个项目应该有多大,但现在可以让你控制有多少列。例如,这将创建五列:

struct ContentView: View {
    let data = (1...100).map { "Item \($0)" }

    let columns = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(data, id: \.self) { item in
                    Text(item)
                }
            }
            .padding(.horizontal)
        }
        .frame(maxHeight: 300)
    }
}

🔴 第三种选择是使用固定尺寸。例如,这将使第一列正好是100点宽,并允许第二列填满所有剩余的空间:

struct ContentView: View {
    let data = (1...100).map { "Item \($0)" }

    let columns = [
        GridItem(.fixed(100)),
        GridItem(.flexible()),
    ]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(data, id: \.self) { item in
                    Text(item)
                }
            }
            .padding(.horizontal)
        }
        .frame(maxHeight: 300)
    }
}

🔴 您也可以使用LazyHGrid来创建一个水平滚动的网格,它的工作方式基本相同,只是它在其初始化器中接受行。
例如,我们可以创建10个并排的标题图像,它们像这样水平滚动:

struct ContentView: View {
    let items = 1...50

    let rows = [
        GridItem(.fixed(50)),
        GridItem(.fixed(50))
    ]

    var body: some View {
        ScrollView(.horizontal) {
            LazyHGrid(rows: rows, alignment: .center) {
                ForEach(items, id: \.self) { item in
                    Image(systemName: "\(item).circle.fill")
                        .font(.largeTitle)
                }
            }
            .frame(height: 150)
        }
    }
}

🔴 正如您所看到的,创建水平和垂直网格所需的代码几乎相同,只是将行改为列。
如果您需要支持iOS 13,您将无法访问LazyHGrid或LazyVGrid,因此请阅读下面的替代方案。
SwiftUI为我们提供了用于垂直布局的VStack和用于水平布局的HStack,但没有任何东西可以同时做到这两点-没有任何东西可以在网格结构中布局视图。
幸运的是,我们可以通过利用SwiftUI的视图构建器系统自己编写一个。这意味着编写一个必须使用行和列计数创建的类型,以及一个闭包,它可以运行以检索网格中给定单元格的视图。然后,在主体内部,它可以循环遍历所有行和列,并在VStack和HStack中创建单元格,以创建网格,每次调用视图闭包来询问单元格中应该有什么。
在代码中,它看起来像这样:

struct GridStack<Content: View>: View {
    let rows: Int
    let columns: Int
    let content: (Int, Int) -> Content

    var body: some View {
        VStack {
            ForEach(0 ..< rows, id: \.self) { row in
                HStack {
                    ForEach(0 ..< columns, id: \.self) { column in
                        content(row, column)
                    }
                }
            }
        }
    }

    init(rows: Int, columns: Int, @ViewBuilder content: @escaping (Int, Int) -> Content) {
        self.rows = rows
        self.columns = columns
        self.content = content
    }
}

// An example view putting GridStack into practice.
struct ContentView: View {
    var body: some View {
        GridStack(rows: 4, columns: 4) { row, col in
            Image(systemName: "\(row * 4 + col).circle")
            Text("R\(row) C\(col)")
        }
    }
}

创建一个4x 4网格,每个单元格中包含图像和文本。
这是对这段代码的引用👇
enter link description here
快乐编码)

相关问题