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

Commit 50c14fa

Browse files
authored
More examples (#91)
* sectioned grid ios * layout and examples
1 parent 1f9807e commit 50c14fa

17 files changed

+345
-47
lines changed

GridDemo iOS/ContentView.swift

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ struct ContentView: View {
1919
Text("Staggered Grid")
2020
}
2121
}
22+
23+
NavigationLink(destination: SectionedGridView()) {
24+
HStack {
25+
Image(systemName: "rectangle.grid.1x2.fill")
26+
Text("Sectioned Grid")
27+
}
28+
}
29+
30+
NavigationLink(destination: StaticGridView()) {
31+
HStack {
32+
Image(systemName: "circle.grid.2x2.fill")
33+
Text("Static Grid")
34+
}
35+
}
2236
}
2337
}
2438
.listStyle(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import SwiftUI
2+
import Grid
3+
4+
struct SectionedGridView: View {
5+
var body: some View {
6+
ScrollView {
7+
ForEach(1..<8) { section in
8+
Section {
9+
HStack {
10+
Text("Section \(section)").font(.headline).fontWeight(.bold)
11+
Spacer()
12+
}
13+
14+
Grid(self.rangeFor(section: section), id: \.self) { index in
15+
Rectangle()
16+
.foregroundColor(.clear)
17+
.background(
18+
Image("\(index)")
19+
.renderingMode(.original)
20+
.resizable()
21+
.scaledToFill()
22+
)
23+
.clipped()
24+
.clipShape(RoundedRectangle(cornerRadius: 4))
25+
}
26+
27+
Spacer(minLength: 16)
28+
}
29+
}
30+
31+
.padding(8)
32+
}
33+
.navigationBarTitle("Sectioned Grid", displayMode: .inline)
34+
.gridStyle(
35+
ModularGridStyle(columns: .min(80), rows: .fixed(80), spacing: 4)
36+
)
37+
}
38+
39+
private func rangeFor(section: Int) -> Range<Int> {
40+
switch section {
41+
case 1: return Range(1...10)
42+
case 2: return Range(11...15)
43+
case 3: return Range(16...26)
44+
case 4: return Range(27...35)
45+
case 5: return Range(36...38)
46+
case 6: return Range(39...55)
47+
case 7: return Range(56...69)
48+
default:
49+
fatalError()
50+
}
51+
}
52+
}
53+
54+
struct SectionedGridView_Previews: PreviewProvider {
55+
static var previews: some View {
56+
SectionedGridView()
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import SwiftUI
2+
import Grid
3+
4+
struct StaticGridView: View {
5+
var body: some View {
6+
ScrollView {
7+
Grid {
8+
Capsule().foregroundColor(.random)
9+
Capsule().foregroundColor(.random)
10+
Capsule().foregroundColor(.random)
11+
Capsule().foregroundColor(.random)
12+
Capsule().foregroundColor(.random)
13+
Capsule().foregroundColor(.random)
14+
Capsule().foregroundColor(.random)
15+
Capsule().foregroundColor(.random)
16+
Capsule().foregroundColor(.random)
17+
Capsule().foregroundColor(.random)
18+
}
19+
.padding(16)
20+
.frame(height: 300)
21+
}
22+
.navigationBarTitle("Static Grid", displayMode: .inline)
23+
.gridStyle(
24+
ModularGridStyle(columns: 5, rows: 2, spacing: 16)
25+
)
26+
}
27+
}
28+
29+
struct StaticGridView_Previews: PreviewProvider {
30+
static var previews: some View {
31+
StaticGridView()
32+
}
33+
}

GridDemo macOS/ContentView.swift

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ struct ContentView: View {
1616
NavigationLink(destination: SectionedGridView()) {
1717
Text("Sectioned Grid")
1818
}
19+
20+
NavigationLink(destination: StaticGridView()) {
21+
Text("Static Grid")
22+
}
1923
}
2024
}
2125
.frame(minWidth: 200, maxWidth: 300)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import SwiftUI
2+
import Grid
3+
4+
struct StaticGridView: View {
5+
var body: some View {
6+
ScrollView {
7+
Grid {
8+
Capsule().foregroundColor(.random)
9+
Capsule().foregroundColor(.random)
10+
Capsule().foregroundColor(.random)
11+
Capsule().foregroundColor(.random)
12+
Capsule().foregroundColor(.random)
13+
Capsule().foregroundColor(.random)
14+
Capsule().foregroundColor(.random)
15+
Capsule().foregroundColor(.random)
16+
Capsule().foregroundColor(.random)
17+
Capsule().foregroundColor(.random)
18+
}
19+
.padding(16)
20+
.frame(height: 300)
21+
}
22+
.gridStyle(
23+
ModularGridStyle(columns: 5, rows: 2, spacing: 16)
24+
)
25+
}
26+
}
27+
28+
struct StaticGridView_Previews: PreviewProvider {
29+
static var previews: some View {
30+
StaticGridView()
31+
}
32+
}

GridDemo.xcodeproj/project.pbxproj

+42-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
/* Begin PBXBuildFile section */
1010
FA6203C323F8AD77009CB0C9 /* Grid in Frameworks */ = {isa = PBXBuildFile; productRef = FA6203C223F8AD77009CB0C9 /* Grid */; };
11-
FA9FFB6D242FFECD0047D145 /* SectionedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9FFB6C242FFECD0047D145 /* SectionedGrid.swift */; };
11+
FA9FFB6D242FFECD0047D145 /* SectionedGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9FFB6C242FFECD0047D145 /* SectionedGridView.swift */; };
12+
FA9FFB70243005B80047D145 /* SectionedGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9FFB6F243005B80047D145 /* SectionedGridView.swift */; };
13+
FA9FFB74243008060047D145 /* StaticGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9FFB73243008060047D145 /* StaticGridView.swift */; };
1214
FAA2C96C23DEAECC00FBDE39 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA2C96B23DEAECC00FBDE39 /* SceneDelegate.swift */; };
1315
FAA2C96E23DEAECC00FBDE39 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA2C96D23DEAECC00FBDE39 /* ContentView.swift */; };
1416
FAA2C97623DEAECD00FBDE39 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FAA2C97423DEAECD00FBDE39 /* LaunchScreen.storyboard */; };
@@ -66,6 +68,7 @@
6668
FAA2CA5523DEB66A00FBDE39 /* StaggeredGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA2CA5323DEB66900FBDE39 /* StaggeredGridView.swift */; };
6769
FAA2CA5923DEB73200FBDE39 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = FAA2CA5823DEB73200FBDE39 /* README.md */; };
6870
FAAA2FCD241C42E4007021F7 /* ImageDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAA2FCC241C42E4007021F7 /* ImageDetailView.swift */; };
71+
FAC1C78B2430694C00FFA885 /* StaticGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC1C78A2430694C00FFA885 /* StaticGridView.swift */; };
6972
FAC9D4DE23DF8CE20007B7DD /* Grid in Frameworks */ = {isa = PBXBuildFile; productRef = FAC9D4DD23DF8CE20007B7DD /* Grid */; };
7073
FAC9D4E023DF8CE90007B7DD /* Grid in Frameworks */ = {isa = PBXBuildFile; productRef = FAC9D4DF23DF8CE90007B7DD /* Grid */; };
7174
FAC9D4E223DF8CEE0007B7DD /* Grid in Frameworks */ = {isa = PBXBuildFile; productRef = FAC9D4E123DF8CEE0007B7DD /* Grid */; };
@@ -114,7 +117,9 @@
114117
/* End PBXCopyFilesBuildPhase section */
115118

116119
/* Begin PBXFileReference section */
117-
FA9FFB6C242FFECD0047D145 /* SectionedGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionedGrid.swift; sourceTree = "<group>"; };
120+
FA9FFB6C242FFECD0047D145 /* SectionedGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionedGridView.swift; sourceTree = "<group>"; };
121+
FA9FFB6F243005B80047D145 /* SectionedGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionedGridView.swift; sourceTree = "<group>"; };
122+
FA9FFB73243008060047D145 /* StaticGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticGridView.swift; sourceTree = "<group>"; };
118123
FAA2C96723DEAECC00FBDE39 /* GridDemo iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "GridDemo iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
119124
FAA2C96B23DEAECC00FBDE39 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
120125
FAA2C96D23DEAECC00FBDE39 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -171,7 +176,8 @@
171176
FAA2CA5323DEB66900FBDE39 /* StaggeredGridView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaggeredGridView.swift; sourceTree = "<group>"; };
172177
FAA2CA5823DEB73200FBDE39 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
173178
FAAA2FCC241C42E4007021F7 /* ImageDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDetailView.swift; sourceTree = "<group>"; };
174-
FAC9D4DC23DF8C750007B7DD /* */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ""; sourceTree = SOURCE_ROOT; };
179+
FAC1C7882430682100FFA885 /* swiftui-grid */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "swiftui-grid"; sourceTree = "<group>"; };
180+
FAC1C78A2430694C00FFA885 /* StaticGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticGridView.swift; sourceTree = "<group>"; };
175181
/* End PBXFileReference section */
176182

177183
/* Begin PBXFrameworksBuildPhase section */
@@ -213,11 +219,27 @@
213219
FA9FFB6B242FFE510047D145 /* SectionedGrid */ = {
214220
isa = PBXGroup;
215221
children = (
216-
FA9FFB6C242FFECD0047D145 /* SectionedGrid.swift */,
222+
FA9FFB6C242FFECD0047D145 /* SectionedGridView.swift */,
217223
);
218224
path = SectionedGrid;
219225
sourceTree = "<group>";
220226
};
227+
FA9FFB6E2430057F0047D145 /* SectionedGrid */ = {
228+
isa = PBXGroup;
229+
children = (
230+
FA9FFB6F243005B80047D145 /* SectionedGridView.swift */,
231+
);
232+
path = SectionedGrid;
233+
sourceTree = "<group>";
234+
};
235+
FA9FFB72243007EA0047D145 /* StaticGrid */ = {
236+
isa = PBXGroup;
237+
children = (
238+
FA9FFB73243008060047D145 /* StaticGridView.swift */,
239+
);
240+
path = StaticGrid;
241+
sourceTree = "<group>";
242+
};
221243
FAA2C93B23DEAD2600FBDE39 = {
222244
isa = PBXGroup;
223245
children = (
@@ -230,7 +252,7 @@
230252
FAA2CA3B23DEB64800FBDE39 /* GridDemo tvOS */,
231253
FAA2C94923DEAE7B00FBDE39 /* Products */,
232254
FAA2C99423DEB0A700FBDE39 /* Frameworks */,
233-
FAC9D4DC23DF8C750007B7DD /* */,
255+
FAC1C7882430682100FFA885 /* swiftui-grid */,
234256
);
235257
sourceTree = "<group>";
236258
};
@@ -250,6 +272,8 @@
250272
FAA2C96823DEAECC00FBDE39 /* GridDemo iOS */ = {
251273
isa = PBXGroup;
252274
children = (
275+
FAC1C7892430693900FFA885 /* StaticGrid */,
276+
FA9FFB6E2430057F0047D145 /* SectionedGrid */,
253277
FAA2C98823DEB00100FBDE39 /* ModularGrid */,
254278
FAA2C98B23DEB00100FBDE39 /* StaggeredGrid */,
255279
FAA2C97B23DEAF9200FBDE39 /* AppDelegate.swift */,
@@ -311,6 +335,7 @@
311335
FAA2C99D23DEB26200FBDE39 /* GridDemo macOS */ = {
312336
isa = PBXGroup;
313337
children = (
338+
FA9FFB72243007EA0047D145 /* StaticGrid */,
314339
FA9FFB6B242FFE510047D145 /* SectionedGrid */,
315340
FAA2C9B323DEB31800FBDE39 /* ModularGrid */,
316341
FAA2C9B623DEB31800FBDE39 /* StaggeredGrid */,
@@ -442,6 +467,14 @@
442467
path = StaggeredGrid;
443468
sourceTree = "<group>";
444469
};
470+
FAC1C7892430693900FFA885 /* StaticGrid */ = {
471+
isa = PBXGroup;
472+
children = (
473+
FAC1C78A2430694C00FFA885 /* StaticGridView.swift */,
474+
);
475+
path = StaticGrid;
476+
sourceTree = "<group>";
477+
};
445478
/* End PBXGroup section */
446479

447480
/* Begin PBXNativeTarget section */
@@ -683,6 +716,7 @@
683716
buildActionMask = 2147483647;
684717
files = (
685718
FAA2C98523DEAFF100FBDE39 /* Item.swift in Sources */,
719+
FA9FFB70243005B80047D145 /* SectionedGridView.swift in Sources */,
686720
FAA2C99123DEB00100FBDE39 /* StaggeredGridView.swift in Sources */,
687721
FAA2C99023DEB00100FBDE39 /* StaggeredGridSettingsView.swift in Sources */,
688722
FAAA2FCD241C42E4007021F7 /* ImageDetailView.swift in Sources */,
@@ -693,14 +727,16 @@
693727
FAA2C96E23DEAECC00FBDE39 /* ContentView.swift in Sources */,
694728
FAA2C98F23DEB00100FBDE39 /* ModularGridSettingsView.swift in Sources */,
695729
FAA2C98E23DEB00100FBDE39 /* ModularGridView.swift in Sources */,
730+
FAC1C78B2430694C00FFA885 /* StaticGridView.swift in Sources */,
696731
);
697732
runOnlyForDeploymentPostprocessing = 0;
698733
};
699734
FAA2C99823DEB26200FBDE39 /* Sources */ = {
700735
isa = PBXSourcesBuildPhase;
701736
buildActionMask = 2147483647;
702737
files = (
703-
FA9FFB6D242FFECD0047D145 /* SectionedGrid.swift in Sources */,
738+
FA9FFB6D242FFECD0047D145 /* SectionedGridView.swift in Sources */,
739+
FA9FFB74243008060047D145 /* StaticGridView.swift in Sources */,
704740
FAA2C9B023DEB26B00FBDE39 /* Item.swift in Sources */,
705741
FAA2C9AF23DEB26B00FBDE39 /* Color+Random.swift in Sources */,
706742
FAA2C9BB23DEB31900FBDE39 /* StaggeredGridSettingsView.swift in Sources */,

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2019 SwiftExtensions.
3+
Copyright (c) 2020 SpaceNation Inc.
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ SwiftUI Grid view layout with custom styles.
66
## Features
77
- ZStack based layout
88
- Vertical and horizontal scrolling
9-
- Supports grid of grids, each with it's own style
109
- Supports all apple platforms
1110
- Custom styles (ModularGridStyle, StaggeredGridStyle)
1211
- SwiftUI code patterns (StyleStructs, EnvironmentValues, ViewBuilder)

Sources/Grid/Grid.swift

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import SwiftUI
33
/// A view that arranges its children in a grid.
44
public struct Grid<Content>: View where Content: View {
55
@Environment(\.gridStyle) private var style
6-
@State var preferences: GridPreferences = .init(items: [])
6+
@State var preferences: GridPreferences = GridPreferences(size: .zero, items: [])
77
let items: [GridItem]
88

99
public var body: some View {
@@ -15,8 +15,8 @@ public struct Grid<Content>: View where Content: View {
1515
width: self.style.autoWidth ? self.preferences[item.id]?.bounds.width : nil,
1616
height: self.style.autoHeight ? self.preferences[item.id]?.bounds.height : nil
1717
)
18-
.alignmentGuide(.leading, computeValue: { _ in self.preferences[item.id]?.bounds.origin.x ?? 0 })
19-
.alignmentGuide(.top, computeValue: { _ in self.preferences[item.id]?.bounds.origin.y ?? 0 })
18+
.alignmentGuide(.leading, computeValue: { _ in geometry.size.width - (self.preferences[item.id]?.bounds.origin.x ?? 0) })
19+
.alignmentGuide(.top, computeValue: { _ in geometry.size.height - (self.preferences[item.id]?.bounds.origin.y ?? 0) })
2020
.background(GridPreferencesModifier(id: item.id, bounds: self.preferences[item.id]?.bounds ?? .zero))
2121
.anchorPreference(key: GridItemBoundsPreferencesKey.self, value: .bounds) { [geometry[$0]] }
2222
}
@@ -25,14 +25,14 @@ public struct Grid<Content>: View where Content: View {
2525
self.style.transform(preferences: &$0, in: geometry.size)
2626
}
2727
}
28-
.onPreferenceChange(GridPreferencesKey.self) { preferences in
29-
self.preferences = preferences
30-
}
3128
.frame(
32-
width: self.style.axis == .horizontal ? self.preferences.size.width : nil,
33-
height: self.style.axis == .vertical ? self.preferences.size.height : nil,
29+
minWidth: self.style.axis == .horizontal ? self.preferences.size.width : nil,
30+
minHeight: self.style.axis == .vertical ? self.preferences.size.height : nil,
3431
alignment: .topLeading
3532
)
33+
.onPreferenceChange(GridPreferencesKey.self) { preferences in
34+
self.preferences = preferences
35+
}
3636
}
3737
}
3838

Sources/Grid/Styles/ModularGridStyle.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -42,34 +42,34 @@ public struct ModularGridStyle: GridStyle {
4242
)
4343
)
4444

45-
preferences.items = layoutPreferences(
45+
preferences = layoutPreferences(
4646
tracks: computedTracksCount,
4747
spacing: self.spacing,
4848
axis: self.axis,
4949
itemSize: itemSize,
50-
preferences: preferences.items
50+
preferences: preferences
5151
)
5252
}
5353

54-
private func layoutPreferences(tracks: Int, spacing: CGFloat, axis: Axis, itemSize: CGSize, preferences: [GridPreferences.Item]) -> [GridPreferences.Item] {
54+
private func layoutPreferences(tracks: Int, spacing: CGFloat, axis: Axis, itemSize: CGSize, preferences: GridPreferences) -> GridPreferences {
5555
var tracksLengths = Array(repeating: CGFloat(0.0), count: tracks)
56-
var newPreferences: [GridPreferences.Item] = []
56+
var newPreferences: GridPreferences = GridPreferences(items: [])
5757

58-
preferences.forEach { preference in
58+
preferences.items.forEach { preference in
5959
if let minValue = tracksLengths.min(), let indexMin = tracksLengths.firstIndex(of: minValue) {
6060
let itemSizeWidth = itemSize.width
6161
let itemSizeHeight = itemSize.height
6262
let width = axis == .vertical ? itemSizeWidth * CGFloat(indexMin) + CGFloat(indexMin) * spacing : tracksLengths[indexMin]
6363
let height = axis == .vertical ? tracksLengths[indexMin] : itemSizeHeight * CGFloat(indexMin) + CGFloat(indexMin) * spacing
6464

65-
let origin = CGPoint(x: 0 - width, y: 0 - height)
65+
let origin = CGPoint(x: width, y: height)
6666
tracksLengths[indexMin] += (axis == .vertical ? itemSizeHeight : itemSizeWidth) + spacing
6767

68-
newPreferences.append(
69-
GridPreferences.Item(
68+
newPreferences.merge(with:
69+
GridPreferences(items: [GridPreferences.Item(
7070
id: preference.id,
7171
bounds: CGRect(origin: origin, size: CGSize(width: itemSizeWidth, height: itemSizeHeight))
72-
)
72+
)])
7373
)
7474
}
7575
}

0 commit comments

Comments
 (0)