@@ -3,61 +3,104 @@ import SwiftUI
3
3
/// A view that arranges its children in a grid.
4
4
@available ( iOS 13 . 0 , OSX 10 . 15 , * )
5
5
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
9
10
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
22
12
23
13
public var body : some View {
24
14
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 ) )
35
25
}
36
- . padding ( )
26
+
37
27
}
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
+ // }
38
45
}
39
- }
40
46
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)
43
52
}
44
53
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)
47
63
}
48
64
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 )
51
67
}
52
68
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
58
102
}
59
103
}
60
-
61
104
}
62
105
63
106
#if DEBUG
0 commit comments