Skip to content
This repository was archived by the owner on Dec 27, 2020. It is now read-only.

Commit 58ccd47

Browse files
committed
zstack
1 parent eafea07 commit 58ccd47

File tree

7 files changed

+126
-65
lines changed

7 files changed

+126
-65
lines changed

Examples/GridExamples.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@
159159
FA90215C230B354900BF9341 /* GridExamples */ = {
160160
isa = PBXGroup;
161161
children = (
162-
FA902169230B39C800BF9341 /* AutoColumnLayoutView.swift */,
163162
FA902166230B398200BF9341 /* OneColumnLayoutView.swift */,
163+
FA902169230B39C800BF9341 /* AutoColumnLayoutView.swift */,
164164
FA90216C230B3EC100BF9341 /* PerformanceLayoutView.swift */,
165165
FA6ED892231090FF00651DD9 /* BuilderLayoutView.swift */,
166166
FA902160230B379D00BF9341 /* Color+Random.swift */,

Examples/GridExamples/AutoColumnLayoutView.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import Grid
33

44
struct AutoColumnLayoutView: View {
55
var body: some View {
6-
Grid(0...100, minimumItemWidth: 120) { number in
7-
Card(title: "\(number)")
8-
.frame(height: 100)
6+
ScrollView {
7+
Grid(0...100, minItemWidth: 120, itemHeight: 100) { number in
8+
Card(title: "\(number)")
9+
}
10+
.padding()
911
}
1012
}
1113
}

Examples/GridExamples/BuilderLayoutView.swift

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,27 @@ import Grid
33

44
struct BuilderLayoutView: View {
55
var body: some View {
6-
VStack(alignment: .center) {
7-
Section(header: Text("Section 1")) {
8-
Grid {
9-
ForEach(0...10, id: \.self) { _ in
10-
Rectangle()
11-
.foregroundColor(.random)
12-
.frame(height: 20)
6+
ScrollView {
7+
VStack(alignment: .center) {
8+
Section(header: Text("Section 1")) {
9+
Grid(itemHeight: 20) {
10+
ForEach(0...10, id: \.self) { _ in
11+
Rectangle()
12+
.foregroundColor(.random)
13+
}
1314
}
1415
}
15-
}
16-
17-
Section(header: Text("Section 2")) {
18-
Grid {
19-
ForEach(0...10, id: \.self) { _ in
20-
Rectangle()
21-
.foregroundColor(.random)
22-
.frame(height: 20)
16+
17+
Section(header: Text("Section 2")) {
18+
Grid(itemHeight: 20) {
19+
ForEach(0...10, id: \.self) { _ in
20+
Rectangle()
21+
.foregroundColor(.random)
22+
}
2323
}
2424
}
2525
}
26+
.padding()
2627
}
2728
}
2829
}

Examples/GridExamples/OneColumnLayoutView.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import Grid
44
struct OneColumnLayoutView: View {
55
var body: some View {
66
GeometryReader { geometry in
7-
Grid(0...100, minimumItemWidth: geometry.size.width) { number in
8-
Card(title: "\(number)")
9-
.frame(height: 300)
7+
ScrollView(.vertical) {
8+
Grid(0...100, minItemWidth: geometry.size.width, itemHeight: 300) { number in
9+
Card(title: "\(number)")
10+
}
11+
.padding()
1012
}
1113
}
1214

Examples/GridExamples/PerformanceLayoutView.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import Grid
33

44
struct PerformanceLayoutView: View {
55
var body: some View {
6-
Grid(0...5000, minimumItemWidth: 20, spacing: 1) { number in
7-
Rectangle()
8-
.foregroundColor(.random)
9-
.frame(height: 20)
6+
ScrollView {
7+
Grid(0...5000, minItemWidth: 20, itemHeight: 20) { number in
8+
Rectangle()
9+
.foregroundColor(.random)
10+
}
1011
}
1112
}
1213
}

Sources/Grid/Grid+Inits.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import SwiftUI
2+
3+
extension Grid {
4+
public init<Data: RandomAccessCollection>(_ data: Data, minItemWidth: CGFloat = 100, itemHeight: CGFloat = 100, spacing: CGFloat = 8, @ViewBuilder content: @escaping (Data.Element) -> Content) {
5+
self.init(items: data.map({ AnyView(content($0)) }), minItemWidth: minItemWidth, itemHeight: itemHeight, spacing: spacing)
6+
}
7+
8+
public init<Data: RandomAccessCollection, ID, Item: View>(minItemWidth: CGFloat = 100, itemHeight: CGFloat = 100, spacing: CGFloat = 8, @ViewBuilder content: () -> Content) where Content == ForEach<Data, ID, Item> {
9+
let views = content()
10+
self.init(items: views.data.map { AnyView(views.content($0)) }, minItemWidth: minItemWidth, itemHeight: itemHeight, spacing: spacing)
11+
}
12+
}

Sources/Grid/Grid.swift

Lines changed: 82 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,104 @@ import SwiftUI
33
/// A view that arranges its children in a grid.
44
@available(iOS 13.0, OSX 10.15, *)
55
public struct Grid<Content> : View where Content : View {
6-
private let items: [AnyView]
7-
private let minimumItemWidth: CGFloat
8-
private let spacing: CGFloat
6+
let items: [AnyView]
7+
let minItemWidth: CGFloat
8+
let itemHeight: CGFloat
9+
let spacing: CGFloat
910

10-
public init<Data: RandomAccessCollection>(_ data: Data, minimumItemWidth: CGFloat = 300, spacing: CGFloat = 8, @ViewBuilder content: @escaping (Data.Element) -> Content) {
11-
self.items = data.map({ AnyView(content($0)) })
12-
self.spacing = spacing
13-
self.minimumItemWidth = minimumItemWidth
14-
}
15-
16-
public init<Data: RandomAccessCollection, ID, Item: View>(@ViewBuilder content: () -> Content) where Content == ForEach<Data, ID, Item> {
17-
let views = content()
18-
self.items = views.data.map { AnyView(views.content($0)) }
19-
self.minimumItemWidth = 300
20-
self.spacing = 8
21-
}
11+
@Environment(\.lastItemPosition) var lastItemPosition
2212

2313
public var body: some View {
2414
GeometryReader { geometry in
25-
ScrollView {
26-
VStack(alignment: .leading, spacing: self.spacing) {
27-
ForEach(0..<self.rowCount(with: geometry), id: \.self) { rowIndex in
28-
HStack(spacing: self.spacing) {
29-
ForEach(0..<self.columnCount(with: geometry), id: \.self) { (columnIndex: Int) -> AnyView? in
30-
self.item(with: geometry, rowIndex: rowIndex, columnIndex: columnIndex)
31-
}
32-
.frame(maxWidth: .infinity)
33-
}
34-
}
15+
// ScrollView {
16+
ZStack {
17+
ForEach(0..<self.items.count, id: \.self) { index in
18+
self.items[index]
19+
.frame(
20+
width: self.itemWidth(for: geometry, minItemWidth: self.minItemWidth),
21+
height: self.itemHeight,
22+
alignment: Alignment(horizontal: .leading, vertical: .top)
23+
)
24+
.position(self.position(at: index, with: geometry, minItemWidth: self.minItemWidth, itemHeight: self.itemHeight))
3525
}
36-
.padding()
26+
3727
}
28+
.frame(height: 4000)
29+
30+
// }
31+
// ScrollView {
32+
33+
// VStack(alignment: .leading, spacing: self.spacing) {
34+
// ForEach(0..<self.rowCount(with: geometry), id: \.self) { rowIndex in
35+
// HStack(spacing: self.spacing) {
36+
// ForEach(0..<self.columnCount(with: geometry), id: \.self) { (columnIndex: Int) -> AnyView? in
37+
// self.item(with: geometry, rowIndex: rowIndex, columnIndex: columnIndex)
38+
// }
39+
// .frame(maxWidth: .infinity)
40+
// }
41+
// }
42+
// }
43+
// .padding()
44+
// }
3845
}
39-
}
4046

41-
func rowCount(with geometry: GeometryProxy) -> Int {
42-
Int((CGFloat(self.items.count) / max(1.0, geometry.size.width / self.minimumItemWidth).rounded(.down)).rounded(.up))
47+
//.fixedSize(horizontal: false, vertical: false)
48+
//.frame(height: CGFloat(self.items.count) * self.itemHeight)
49+
50+
51+
//.frame(height: CGFloat(items.count) * itemHeight)
4352
}
4453

45-
func columnCount(with geometry: GeometryProxy) -> Int {
46-
Int(geometry.size.width / self.minimumItemWidth)
54+
func position(at index: Int, with geometry: GeometryProxy, minItemWidth: CGFloat, itemHeight: CGFloat) -> CGPoint {
55+
let columnCount = Int(geometry.size.width / minItemWidth)
56+
let row: Int = index / max(1, columnCount)
57+
let itemIndexAtRow = index % max(1, columnCount)
58+
let itemWidth = self.itemWidth(for: geometry, minItemWidth: minItemWidth)
59+
let x = (itemWidth / 2) + CGFloat(itemIndexAtRow) * itemWidth
60+
let y = (itemHeight / 2) + CGFloat(row) * itemHeight
61+
_ = environment(\.lastItemPosition, y)
62+
return CGPoint(x: x, y: y)
4763
}
4864

49-
func itemIndex(with geometry: GeometryProxy, rowIndex: Int, columnIndex: Int) -> Int {
50-
rowIndex * max(1, Int(geometry.size.width / self.minimumItemWidth)) + columnIndex
65+
@inlinable func itemWidth(for geometry: GeometryProxy, minItemWidth: CGFloat) -> CGFloat {
66+
geometry.size.width / max(1.0, geometry.size.width / minItemWidth).rounded(.down)
5167
}
5268

53-
func item(with geometry: GeometryProxy, rowIndex: Int, columnIndex: Int) -> AnyView {
54-
if self.itemIndex(with: geometry, rowIndex: rowIndex, columnIndex: columnIndex) <= self.items.count - 1 {
55-
return self.items[self.itemIndex(with: geometry, rowIndex: rowIndex, columnIndex: columnIndex)]
56-
} else {
57-
return AnyView(Spacer())
69+
// private func columnCount(with geometry: GeometryProxy) -> Int {
70+
// Int(geometry.size.width / self.minItemWidth)
71+
// }
72+
//
73+
// private func rowCount(with geometry: GeometryProxy) -> Int {
74+
// Int((CGFloat(self.items.count) / max(1.0, geometry.size.width / self.minItemWidth).rounded(.down)).rounded(.up))
75+
// }
76+
77+
// func itemIndex(with geometry: GeometryProxy, rowIndex: Int, columnIndex: Int) -> Int {
78+
// rowIndex * max(1, Int(geometry.size.width / self.minItemWidth)) + columnIndex
79+
// }
80+
81+
// func item(with geometry: GeometryProxy, rowIndex: Int, columnIndex: Int) -> AnyView {
82+
// if self.itemIndex(with: geometry, rowIndex: rowIndex, columnIndex: columnIndex) <= self.items.count - 1 {
83+
// return self.items[self.itemIndex(with: geometry, rowIndex: rowIndex, columnIndex: columnIndex)]
84+
// } else {
85+
// return AnyView(Spacer())
86+
// }
87+
// }
88+
89+
}
90+
91+
struct LastItemPositionKey: EnvironmentKey {
92+
static let defaultValue: Binding<CGFloat?> = .constant(nil)
93+
}
94+
95+
extension EnvironmentValues {
96+
var lastItemPosition: Binding<CGFloat?> {
97+
get {
98+
return self[LastItemPositionKey.self]
99+
}
100+
set {
101+
self[LastItemPositionKey.self] = newValue
58102
}
59103
}
60-
61104
}
62105

63106
#if DEBUG

0 commit comments

Comments
 (0)