Blockchain ク gainst to the list

This article uses the current latest version of Xcode 12 + macOS Big sur + iOS14

The Grid layout

LazyVGrid and LazyHGrid have a vertical grid layout and a horizontal grid layout. The new layout manager for iOS14, like LazyVStack and LazyHStack, has Lazy layout, which means that these two layout managers will only render the child elements that need to be displayed.

LazyVGrid

LazyVGrid populates the layout by specifying the number of columns

  LazyVGrid(columns: [GridItem(.fixed(100)), GridItem(.fixed(100)), GridItem(.fixed(100))]) {ForEach(0 ..< 30){ index in
          RoundedRectangle(cornerRadius: 5)
              .foregroundColor(Color(hue: 0.03 * Double(index) , saturation: 1, brightness: 1))
              .frame(height: 50)
              .overlay(Text("\(index)"))
      }
  }
  .padding()
Copy the code

ForEach fills 30 cells by specifying 3 columns with width 100. ForEach will be discussed later. The result is as follows:

The LazyVGrid is populated line by line from the top, row by row, and row by row by row, which is easy to see from the sequence shown in the figure above.

Row spacing can be adjusted by setting spacing for the LazyVGrid.

LazyVGrid(columns: [GridItem(.fixed(100)), GridItem(.fixed(100)), GridItem(.fixed(100))], spacing: 30) {ForEach(0 ..< 30){ index in
      RoundedRectangle(cornerRadius: 5)
          .foregroundColor(Color(hue: 0.03 * Double(index) , saturation: 1, brightness: 1))
          .frame(height: 50)
          .overlay(Text("\(index)"))
  }
}
.padding()
Copy the code

The effect is as follows:

LazyVGrid allows Header and Footer to hover at the top and bottom of a scroll by setting the PinnedViews type. Section sets header and footer for Section

VStack {
  ScrollView {
      LazyVGrid(columns: [GridItem(.fixed(100)), GridItem(.fixed(100)), GridItem(.fixed(100))], pinnedViews: [.sectionHeaders, .sectionFooters]){
          ForEach(0 ..< 5){ index in
              Section(header: Text("Header \(index)")
                          .bold()
                          .font(.title)
                          .frame(maxWidth: .infinity, alignment: .leading)
                          .background(Color.white),
                      footer: Text("Footer \(index)")
                              .bold()
                              .font(.title)
                              .frame(maxWidth: .infinity, alignment: .leading)
                              .background(Color.white)
              ) {
                  ForEach(0 ..< 10){ idx in
                      RoundedRectangle(cornerRadius: 5)
                          .foregroundColor(Color(hue: 0.03 * Double(index * 10 + idx) , saturation: 1, brightness: 1))
                          .frame(height: 50)
                          .overlay(Text("\(index * 10 + idx)"))
                  }
              }
          }
      }
      .padding()
  }
}
.clipped()
Copy the code

Click the play button on the top of the preview emulator to enter the dynamic preview. You can scroll the ScrollView. The effect is basically the same as UITableView’s header and footer hover

The GridItem controls the width of the grid by setting Size:

  • fixedDetermines the lattice width by specifying a fixed size
  • flexibleThe elastic size will divide the remaining space with other flexible cells, and you can set the desired maximum and minimum values. If the minimum value specified is too large, it may go off-screen
  • adaptiveAdaptive distribution, this size will provide one or more grids. You need to specify a minimum value, you can also set a maximum value, and then according to the minimum value, divide the occupied area into several grids that meet the maximum value of the minimum value. You can understandadaptiveAs aflexibleLarge grid, after obtaining the space and then bisect this large grid into a number of small grid to meet the set value.

The GeometryReader is a special View that retrieves some size coordinates, discussed later:

LazyVGrid(columns: [GridItem(.flexible()), GridItem(.adaptive(minimum: 50), spacing: 0)]) {ForEach(0 ..< 30){ idx in
        GeometryReader{r in
            RoundedRectangle(cornerRadius: 5)
                .foregroundColor(Color(hue: 0.01 * Double(idx) , saturation: 1, brightness: 1))
                .overlay(Text("\(r.size.width)"))
        }
        .frame(height: 50)

    }
}
.padding()
Copy the code

The effect is as follows:

It’s easy to see that the flexble cell on the left is the sum of the width of the three little cells on the right.

GridItem controls the spacing between grids by setting spacing to a value for spacing

LazyVGrid(columns: [GridItem(.flexible(), spacing: 10), GridItem(.flexible(), spacing: 100), GridItem(.flexible(), spacing: 50)]) {ForEach(0 ..< 30){ idx in
        RoundedRectangle(cornerRadius: 5)
            .foregroundColor(Color(hue: 0.0333 * Double(idx) , saturation: 1, brightness: 1))
        .frame(height: 50)
    }
}
.padding()
Copy the code

The running effect is as follows:

You can see that only the Settings space is added to the right side of the grid.

The height of each row of the LazyVGrid depends on the highest grid size, and the GridItem Alignment controls the position of elements within the grid, similar to the use of the frame Alignment.

LazyVGrid(columns: [GridItem(.flexible(), alignment: .topLeading), GridItem(.flexible(), alignment: .bottomLeading), GridItem(.flexible(),  alignment: .trailing)]){
    ForEach(0 ..< 30){ idx in
        RoundedRectangle(cornerRadius: 5)
            .foregroundColor(Color(hue: 0.0333 * Double(idx) , saturation: 1, brightness: 1))
            .frame(width: CGFloat((idx % 3) + 1) * 20, height: CGFloat((idx % 3) + 1) * 20)
    }
}
.padding()
Copy the code

The running effect is as follows:

LazyHGrid

LazyHGrid and LazyVGrid are similar in usage. LazyHGrid specifies the number of rows and populates the second column from top to bottom.

Strange and clever technology to achieve irregular layout

LazyHGrid and LazyVGrid are fixed format size, how to achieve irregular layout, as shown in the following figure

Let’s start with some simple code:

LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()]){
    RoundedRectangle(cornerRadius: 5)
        .foregroundColor(Color(hue: 0.3 * Double(1) , saturation: 1, brightness: 1))
        .frame(width: 450, height: 100)
    RoundedRectangle(cornerRadius: 5)
        .foregroundColor(Color(hue: 0.3 * Double(2) , saturation: 1, brightness: 1))
        .frame(width: 200,height: 100)
    RoundedRectangle(cornerRadius: 5)
        .foregroundColor(Color(hue: 0.3 * Double(3) , saturation: 1, brightness: 1))
        .frame(width: 50,height: 100)
}
.padding()
Copy the code

Define a 3 column grid, place 3 rectangles, run to see the effect:

LazyVGrid does not crop views beyond the grid.

So I can define a double width cell that fills two of them. Replace the next box with color.clear.

Attached code:

LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]){
      ForEach(0 ..< 11){ idx in
          GeometryReader { r in
              RoundedRectangle(cornerRadius: 5)
                  .foregroundColor(Color(hue: 0.1 * Double(idx) , saturation: 1, brightness: 1))
                  .frame(width: idx = = 6 ? 2 * r.size.width  + 10 : r.size.width )
          }
          .frame(height: 100)
          if idx = = 6 {
              Color.clear
          }
      }
  }
  .padding()
Copy the code