Skip to content

Commit 78541bc

Browse files
authored
Merge pull request #14 from seek-oss/feature/flow-layout-stack
Add new FlowLayoutStack
2 parents 53b797c + 62ab2f9 commit 78541bc

19 files changed

+455
-583
lines changed

stackable.xcodeproj/project.xcworkspace/contents.xcworkspacedata renamed to .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// swift-tools-version: 5.9
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "Stackable",
8+
platforms: [
9+
.iOS(.v15)
10+
],
11+
products: [
12+
.library(
13+
name: "Stackable",
14+
targets: ["Stackable"]),
15+
],
16+
dependencies: [],
17+
targets: [
18+
.target(
19+
name: "Stackable"
20+
),
21+
.testTarget(
22+
name: "StackableTests",
23+
dependencies: ["Stackable"]
24+
)
25+
]
26+
)

Sources/FlowLayoutStack.swift

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright © 2024 SEEK. All rights reserved.
2+
//
3+
4+
import UIKit
5+
6+
open class FlowLayoutStack: HStack {
7+
let lineSpacing: CGFloat
8+
private var itemSpacing: CGFloat {
9+
spacing
10+
}
11+
12+
public init(
13+
itemSpacing: CGFloat = 0.0,
14+
lineSpacing: CGFloat = 0.0,
15+
width: CGFloat? = nil,
16+
thingsToStack: [Stackable]
17+
) {
18+
self.lineSpacing = lineSpacing
19+
20+
super.init(
21+
spacing: itemSpacing,
22+
layoutMargins: .zero,
23+
thingsToStack: thingsToStack,
24+
width: width
25+
)
26+
}
27+
28+
public convenience init(
29+
itemSpacing: CGFloat = 0.0,
30+
lineSpacing: CGFloat = 0.0,
31+
width: CGFloat? = nil,
32+
thingsToStack: () -> [Stackable]
33+
) {
34+
self.init(
35+
itemSpacing: itemSpacing,
36+
lineSpacing: lineSpacing,
37+
width: width,
38+
thingsToStack: thingsToStack()
39+
)
40+
}
41+
42+
open override func framesForLayout(_ width: CGFloat, origin: CGPoint) -> [CGRect] {
43+
var frames: [CGRect] = []
44+
var currentY = origin.y
45+
var currentX = origin.x
46+
47+
func moveToNextRow() {
48+
currentX = 0
49+
currentY = frames.reduce(0) { result, rect in
50+
max(
51+
result,
52+
rect.origin.y + rect.size.height
53+
)
54+
} + lineSpacing
55+
}
56+
57+
for stackable in self.visibleThingsToStack() {
58+
let stackableWidth = getWidth(
59+
for: stackable,
60+
width: width
61+
)
62+
63+
if currentX + stackableWidth > width {
64+
moveToNextRow()
65+
}
66+
67+
if let stack = stackable as? Stack {
68+
frames.append(
69+
contentsOf: stack.framesForLayout(
70+
(width - currentX),
71+
origin: .init(
72+
x: currentX,
73+
y: currentY
74+
)
75+
)
76+
)
77+
} else if let item = stackable as? StackableItem {
78+
frames.append(
79+
.init(
80+
x: currentX,
81+
y: currentY,
82+
width: stackableWidth,
83+
height: item.heightForWidth(stackableWidth)
84+
)
85+
)
86+
}
87+
88+
currentX += stackableWidth + itemSpacing
89+
}
90+
91+
return frames
92+
}
93+
94+
private func getWidth(for stackable: Stackable, width: CGFloat) -> CGFloat {
95+
return if let stackableItem = stackable as? StackableItem {
96+
min(
97+
stackableItem.intrinsicContentSize.width,
98+
width
99+
)
100+
} else if let fixedSizeStack = stackable as? Stack, let stackWidth = fixedSizeStack.width {
101+
stackWidth
102+
} else {
103+
stackable.intrinsicContentSize.width
104+
}
105+
}
106+
}

Sources/Info.plist

Lines changed: 0 additions & 26 deletions
This file was deleted.

Sources/Stack.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import UIKit
55

6-
public protocol Stack: class, Stackable {
6+
public protocol Stack: AnyObject, Stackable {
77
var thingsToStack: [Stackable] { get }
88
var spacing: CGFloat { get }
99
var layoutMargins: UIEdgeInsets { get }

Sources/stackable.h

Lines changed: 0 additions & 14 deletions
This file was deleted.

Stackable.podspec

Lines changed: 0 additions & 16 deletions
This file was deleted.

Tests/FixedSizeStackableTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
//
33

44
import Foundation
5-
@testable import stackable
65
import XCTest
6+
@testable import Stackable
77

88
class FixedSizeStackableTests: XCTestCase {
99
func test_view_should_return_expected() {

0 commit comments

Comments
 (0)