Write in the beginning
This article assumes that the reader already knows the basic usage of LazyVGrid+LazyHGrid.
- Fixed: Columns have a fixed width. The width is not affected by the size of the space. A column is displayed
- Flexible: You can specify the minimum and maximum values, depending on the size of the space, but the final display width must be within the range, not infinitely smaller or larger, display a column
- Adaptive: You can specify minimum and maximum values, which are affected by the size of the space, to display as many columns as possible
Note: No spacing is set – the default spacing is 8
Just lift the chestnuts
fixed
[GridItem(.fixed(60)))Copy the code
Conclusion: Regardless of container width, use fixed width and render width of 60
fixed+fixed
[
GridItem(.fixed(60)),
GridItem(.fixed(100)))Copy the code
Conclusion: Regardless of container width, use fixed width and render width of 60 + 8 + 100
flexible
[GridItem(.flexible(minimum: 100, maximum: 200)))Copy the code
Render width Max (min(container width, 200), 100)
flexible+flexible
GridItem(.flexible(minimum: 100)),
GridItem(.flexible(minimum: 180))
Copy the code
Things get interesting. You might have guessed 100+8+180 at first, but it turns out to be completely different. Let’s look at the layout process through calculation.
1. The recommended width is 300, the width is 300-8 = 292 after subtraction of the spacing, so the recommended width of each column is 292/2 = 146. The minimum value is 100 when comparing the first column, so the first column directly uses 146 as the recommended width, the remaining width is 146, and the minimum value is 180 when comparing the second column. Choosing 180 as the suggested width, the final calculated width is 146 + 8 + 180 = 334
Start rendering, (334-8) / 2 = 163, the first column is enough, render width is 163, the second column is not enough, use 180 directly, so the final render effect is 163 + 8 + 180
Note: the display is not centered, the center effect is (326 + 8-300) / 2 = 17 at the end of the first step, and 351-300-17 = 34 when the second step is not drawn, so the final display effect is 17 more on the left and 34 more on the right
And then you think you’re invincible, but reality hits you in the ass. Or [Flexible + Flexible]
GridItem(.flexible(minimum: 180)),
GridItem(.flexible(minimum: 100))
Copy the code
Do not doubt that life, in fact, or the original formula, or the original taste, let us begin
1. The recommended width is 300, and the width is 300-8=292 after subtraction of the spacing, so the recommended width of each column is 292/2 = 146. Compare the first column, and the minimum value is 180, so the first column directly takes up 180, and the remaining width is 292-180 = 112. The minimum value is 100, so the second column can occupy 112, and the final result is 180 + 8 + 112 = 300
2. Start rendering with 300, same as 1
flexible + fixed + flexible
GridItem(.flexible(minimum: 180)),
GridItem(.fixed(minimum: 100)),
GridItem(.flexible(minimum: 100))
Copy the code
1. Start width300
Is after subtracting the fixed width and spacing300 minus 100 minus 8 minus 8 is 184
After subtracting the fixed columns, there are two columns left, so the recommended width of the first column is184/2 is 92
, compared with the first column, the minimum value is180
So the first column is directly occupied180
, the remaining width is184 minus 180 is 4
, compare the second column, the minimum value100
So the second column is occupied100
, the final calculation result is180 plus 8 plus 100 plus 8 plus 100 is 396
The render width of the first column is 280/2 = 140. The minimum value for the first column is 180, so the first column occupies 180. The remaining width is 280-180 = 100, compared to the second column, the minimum value is 100, so the second column occupies 100, rendering, rendering width is 180 + 8 + 100 + 8 + 100 = 396
Note: the renderer starts and ends with the same width, and the display is centered
GridItem(.flexible(minimum: 100)),
GridItem(.fixed(minimum: 100)),
GridItem(.flexible(minimum: 180))
Copy the code
After subtracting the fixed width and spacing, it is 300-100-8-8 = 184. After subtracting the fixed columns, there are two remaining columns, so the recommended width of the first column is 184/2 = 92. Compared with the first column, the minimum value is 100, so 100 is used. The remaining width is 184-100 = 84. Compared with the second column, the minimum value is 180, so the second column occupies 180. The final calculation result is 100 + 8 + 100 + 8 + 180 = 396
2. The render width of the first column is 280/2 = 140. The render width of the first column is 280/2 = 140. The minimum value is 100, so the first column takes up 140 and the remaining width is 280-140 = 140, compared to the second column, the minimum value is 180, so the second column takes up 180 and the final render width is 140 + 8 + 100 + 8 + 180 = 436
Note: start 396 as the initial calculation render, start center layout is 48-300-48, start position is fixed, render width is 436, final render is 48-300-88
Conclusion – Render width = F (f(suggested width))
Step 1: Calculate
Flexible: Select the column width based on the average of the remaining width and the number of remaining columns and the current column limit. Then subtract the column width from the remaining width. Fixed: Direct adaptive: Next chapter - to be determined 4. Finally get the initial render widthCopy the code
Step 2: Render
1. Start from the result of step 1. Repeat Step 1 to Step 5 to get the final rendering resultCopy the code
Following the conclusion step, write the calculation code for this process briefly
extension View {
func draw(_ items: [GridItem].contentWidth: CGFloat)- > [CGFloat] {
let result1 = calculate(items, contentWidth: contentWidth).reduce(into: 0) { $0 + = The $1 }
let spacings = items.dropLast().reduce(into: 0) { $0 + = (The $1.spacing ?? 8)}return calculate(items, contentWidth: result1 + spacings)
}
func calculate(_ items: [GridItem].contentWidth: CGFloat)- > [CGFloat] {
var result = Array<CGFloat>(repeating: 0, count: items.count)
var dynamicWidth = contentWidth
var dynamicCount = items.count
/// Subtract the width of the fixed-width column and the spacing between the columns
for (index, item) in items.enumerated() {
/// The spacing of the last line is not counted
if index ! = items.count - 1 {
dynamicWidth - = (item.spacing ?? 8)}if case .fixed(let width) = item.size {
dynamicCount - = 1
dynamicWidth - = width
}
}
if dynamicCount > 0 {
/// iterate over all columns
for (index, item) in items.enumerated() {
switch item.size {
case let .flexible(minimum, maximum):
let singleWidth = dynamicWidth / CGFloat(dynamicCount)
let width = min(maximum, max(minimum, singleWidth))
result[index] = width
dynamicCount - = 1
dynamicWidth - = width
case .fixed(let width):
result[index] = width
case .adaptive:
// complete the next chapter here
continue
@unknown default:
continue}}}return result
}
}
Copy the code
Supporting the Demo