如何使用SwiftUI2网格创建“像砌体”布局?

时间:2020-07-13 14:27:10

标签: swiftui

SwiftUI 2网格系统是否可以渲染“砌体式”布局?

“砌体”布局如下所示:

Masonry image layout

此布局的显着特征是内容可以跨多列。

对于LazyVGrid或LazyHGrid,这似乎无法自动实现,因为它们依赖于GridItem,后者似乎描述了一列(固定,灵活或自适应)。

如果您认为专栏文章无法实现此设计。

我错过了什么吗?是真的,我们不能制作这种网格吗?

1 个答案:

答案 0 :(得分:1)

我必须承认,我尚未对Lazy Grids进行大量研究,但是正如我看到的一些示例所示,恐怕 方式是不可能的。但是我的编程思想是:一切皆有可能。因此,让我们制定自己的解决方案!这是我的:

struct ContentView: View {
    let items = (1 ... 12).map { "Item \($0)" }
    var range: Range<Int> { 0 ..< Int((Double(items.count) / 3).rounded(.up)) }
    var body: some View {
        GeometryReader { geometry in
            ScrollView {
                LazyVStack { // still some laziness 
                    ForEach(range, id: \.self) { index in
                        HStack(spacing: 0) {
                            if index % 2 == 0 {
                                Text(items[index * 3])
                                    .frame(maxHeight: .infinity)
                                    .frame(width: geometry.size.width * 2/3)
                                    .background(Color(#colorLiteral(red: 0.3427395821, green: 0.7238617539, blue: 0.6179549098, alpha: 1)))
                                VStack(spacing: 0) {
                                    Text(items[index * 3 + 1])
                                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                                        .background(Color(#colorLiteral(red: 0.1351453364, green: 0.1446713805, blue: 0.2671209574, alpha: 1)))
                                    Text(items[index * 3 + 2])
                                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                                        .background(Color(#colorLiteral(red: 0.9248386621, green: 0.3957888484, blue: 0.3508865833, alpha: 1)))
                                }
                                .frame(maxHeight: .infinity)
                                .frame(width: geometry.size.width * 1/3)
                            } else {
                                VStack(spacing: 0) {
                                    Text(items[index * 3])
                                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                                        .background(Color(#colorLiteral(red: 0.1351453364, green: 0.1446713805, blue: 0.2671209574, alpha: 1)))
                                    Text(items[index * 3 + 1])
                                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                                        .background(Color(#colorLiteral(red: 0.9248386621, green: 0.3957888484, blue: 0.3508865833, alpha: 1)))
                                }
                                .frame(maxHeight: .infinity)
                                .frame(width: geometry.size.width * 1/3)
                                Text(items[index * 3 + 2])
                                    .frame(maxHeight: .infinity)
                                    .frame(width: geometry.size.width * 2/3)
                                    .background(Color(#colorLiteral(red: 0.226172477, green: 0.3690122366, blue: 0.3273729682, alpha: 1)))
                            }
                        }
                        .frame(height: geometry.size.width * 6/16)
                    }
                }
            }
        }
        .foregroundColor(.white)
    }
}

说明:

  • 带有let items = ...的行只是一种生成包含字符串“ Item 1”到“ Item 12”的列表的快速方法。
  • 让我们将每组三个项目视为一个“行”。然后变量range将包含行数。
  • 我们为每一行创建一个HStack。在其中,VStack中将有一个大项目和两个小项目。在偶数行(索引%2 == 0)中,VStack将在右侧,在奇数行中,它将在左侧。
  • 我们使用.frame(maxHeight: .infinity)使项目填充可用空间。
  • 但是我们如何在正确的位置获得正确的物品?好了,如您所见,我使用了index * 3index * 3 + 1index * 3 + 2,其中index是行号。我将通过下表进行说明:
    +-------------------------------------------+-------------------------------------------+-------------------------------------------+-------------------------------------------+
    | index = 0                                 | index = 1                                 | index = 2                                 | index = 3                                 |
    +-----------+---------------+---------------+-----------+---------------+---------------+-----------+---------------+---------------+-----------+---------------+---------------+
    | index * 3 | index * 3 + 1 | index * 3 + 2 | index * 3 | index * 3 + 1 | index * 3 + 2 | index * 3 | index * 3 + 1 | index * 3 + 2 | index * 3 | index * 3 + 1 | index * 3 + 2 |
    |    = 0    |      = 1      |      = 2      |    = 3    |      = 4      |      = 5      |    = 6    |      = 7      |      = 8      |    = 9    |      = 10     |      = 11     |
    +-----------+---------------+---------------+-----------+---------------+---------------+-----------+---------------+---------------+-----------+---------------+---------------+