Skip to content

Commit 80410e5

Browse files
committed
New ScrollStackView
1 parent 470ff6d commit 80410e5

File tree

6 files changed

+242
-24
lines changed

6 files changed

+242
-24
lines changed

Example/FrameLayoutKit/CardView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class CardView: UIView {
7878

7979
frameLayout.spacing = 15.0
8080
frameLayout.padding(top: 15, left: 15, bottom: 15, right: 15)
81-
frameLayout.debug = true
81+
// frameLayout.debug = true
8282
addSubview(frameLayout)
8383
}
8484

Example/FrameLayoutKit/ViewController.swift

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,28 @@ import UIKit
1010
import FrameLayoutKit
1111

1212
class ViewController: UIViewController {
13-
let frameLayout = StackFrameLayout(axis: .vertical)
13+
let scrollStackView = ScrollStackView()
1414

1515
override func viewDidLoad() {
1616
super.viewDidLoad()
1717

1818
view.backgroundColor = .lightGray
1919

20-
#if targetEnvironment(macCatalyst)
21-
for _ in 0..<1 {
22-
let cardView = CardView()
23-
view.addSubview(cardView)
24-
frameLayout.add(cardView)
20+
for _ in 0..<5 {
21+
scrollStackView.add(CardView())
2522
}
26-
#else
27-
let cardView = CardView()
28-
view.addSubview(cardView)
29-
frameLayout.add(cardView)
30-
#endif
3123

32-
let numberPadView = NumberPadView()
33-
view.addSubview(numberPadView)
34-
frameLayout.add(numberPadView)
24+
scrollStackView.add(NumberPadView())
3525

36-
frameLayout.spacing = 20
37-
frameLayout.edgeInsets = UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50)
38-
frameLayout.distribution = .center
39-
view.addSubview(frameLayout)
26+
scrollStackView.spacing = 20
27+
scrollStackView.edgeInsets = UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50)
28+
scrollStackView.distribution = .center
29+
view.addSubview(scrollStackView)
4030
}
4131

4232
override func viewDidLayoutSubviews() {
4333
super.viewDidLayoutSubviews()
44-
frameLayout.frame = view.bounds
34+
scrollStackView.frame = view.bounds
4535
}
4636

4737
}

Example/Podfile.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
PODS:
2-
- FrameLayoutKit (4.4.1)
2+
- FrameLayoutKit (4.5.0)
33

44
DEPENDENCIES:
55
- FrameLayoutKit (from `../`)
@@ -9,8 +9,8 @@ EXTERNAL SOURCES:
99
:path: "../"
1010

1111
SPEC CHECKSUMS:
12-
FrameLayoutKit: 59ea4b37f24e6b364048b49f1d5e57e976dca444
12+
FrameLayoutKit: d85f746072cc137c13647fbb2be252bdc0fb1b60
1313

1414
PODFILE CHECKSUM: ac097e09a36888b120812ddf1779def87475dc02
1515

16-
COCOAPODS: 1.9.1
16+
COCOAPODS: 1.9.3

FrameLayoutKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'FrameLayoutKit'
3-
s.version = '4.4.2'
3+
s.version = '4.5.0'
44
s.summary = 'FrameLayoutKit is a super fast and easy to use layout kit'
55
s.description = <<-DESC
66
An auto layout kit helps you to layout your UI easier and more effective
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
//
2+
// ScrollStackView.swift
3+
// FrameLayoutKit
4+
//
5+
// Created by Nam Kennic on 6/23/20.
6+
//
7+
8+
import UIKit
9+
10+
open class ScrollStackView<T: UIView>: UIView {
11+
12+
public var views: [T] = [] {
13+
didSet {
14+
updateLayout()
15+
setNeedsLayout()
16+
}
17+
}
18+
19+
public var firstView: T? {
20+
return frameLayout.firstFrameLayout?.targetView as? T
21+
}
22+
23+
public var lastView: T? {
24+
return frameLayout.lastFrameLayout?.targetView as? T
25+
}
26+
27+
open var spacing: CGFloat {
28+
get {
29+
return frameLayout.spacing
30+
}
31+
set {
32+
frameLayout.spacing = newValue
33+
setNeedsLayout()
34+
}
35+
}
36+
37+
open var edgeInsets: UIEdgeInsets {
38+
get {
39+
return frameLayout.edgeInsets
40+
}
41+
set {
42+
frameLayout.edgeInsets = newValue
43+
setNeedsLayout()
44+
}
45+
}
46+
47+
override open var frame: CGRect {
48+
didSet {
49+
setNeedsLayout()
50+
}
51+
}
52+
53+
override open var bounds: CGRect {
54+
didSet {
55+
setNeedsLayout()
56+
}
57+
}
58+
59+
public var axis: NKLayoutAxis {
60+
get {
61+
return frameLayout.axis
62+
}
63+
set {
64+
frameLayout.axis = newValue
65+
setNeedsLayout()
66+
}
67+
}
68+
69+
public var distribution: NKLayoutDistribution {
70+
get {
71+
return frameLayout.distribution
72+
}
73+
set {
74+
frameLayout.distribution = newValue
75+
setNeedsLayout()
76+
}
77+
}
78+
79+
public let scrollView = UIScrollView()
80+
public let frameLayout = StackFrameLayout(axis: .vertical, distribution: .top)
81+
82+
// MARK: -
83+
84+
convenience public init(views: [T], axis: NKLayoutAxis = .vertical) {
85+
self.init()
86+
87+
self.axis = axis
88+
defer {
89+
self.views = views
90+
}
91+
}
92+
93+
public init() {
94+
super.init(frame: .zero)
95+
96+
scrollView.bounces = true
97+
scrollView.alwaysBounceHorizontal = false
98+
scrollView.alwaysBounceVertical = false
99+
scrollView.isDirectionalLockEnabled = true
100+
scrollView.showsVerticalScrollIndicator = false
101+
scrollView.showsHorizontalScrollIndicator = false
102+
scrollView.clipsToBounds = false
103+
scrollView.delaysContentTouches = false
104+
105+
frameLayout.spacing = 0.0
106+
frameLayout.isIntrinsicSizeEnabled = true
107+
frameLayout.shouldCacheSize = false
108+
scrollView.addSubview(frameLayout)
109+
addSubview(scrollView)
110+
}
111+
112+
required public init?(coder aDecoder: NSCoder) {
113+
super.init(coder: aDecoder)
114+
}
115+
116+
override open func sizeThatFits(_ size: CGSize) -> CGSize {
117+
return frameLayout.sizeThatFits(size)
118+
}
119+
120+
override open func layoutSubviews() {
121+
super.layoutSubviews()
122+
123+
let viewSize = bounds.size
124+
let sizeToFit = axis == .horizontal ? CGSize(width: CGFloat.infinity, height: viewSize.height) : CGSize(width: viewSize.width, height: CGFloat.infinity)
125+
scrollView.contentSize = frameLayout.sizeThatFits(sizeToFit)
126+
scrollView.frame = bounds
127+
128+
var contentFrame = bounds
129+
if axis == .horizontal {
130+
contentFrame.size.width = max(viewSize.width, scrollView.contentSize.width)
131+
scrollView.contentSize.height = min(viewSize.height, scrollView.contentSize.height)
132+
}
133+
else {
134+
contentFrame.size.height = max(viewSize.height, scrollView.contentSize.height)
135+
scrollView.contentSize.width = min(viewSize.width, scrollView.contentSize.width)
136+
}
137+
frameLayout.frame = contentFrame
138+
}
139+
140+
// MARK: -
141+
142+
public func view(at index: Int) -> T? {
143+
return frameLayout.frameLayout(at: index)?.targetView as? T
144+
}
145+
146+
@discardableResult
147+
open func add(_ view: T?) -> FrameLayout {
148+
if let view = view { scrollView.addSubview(view) }
149+
let layout = frameLayout.add(view)
150+
setNeedsLayout()
151+
return layout
152+
}
153+
154+
@discardableResult
155+
open func add(_ views: [T]) -> [FrameLayout] {
156+
var results = [FrameLayout]()
157+
views.forEach { (view) in
158+
results.append(add(view))
159+
}
160+
161+
return results
162+
}
163+
164+
@discardableResult
165+
open func insert(_ view: T?, at index: Int) -> FrameLayout {
166+
if let view = view { scrollView.addSubview(view) }
167+
let layout = frameLayout.insert(view, at: index)
168+
setNeedsLayout()
169+
return layout
170+
}
171+
172+
@discardableResult
173+
open func addSpace(_ size: CGFloat = 0) -> FrameLayout {
174+
let layout = add(T())
175+
layout.fixSize = CGSize(width: axis == .horizontal ? size : 0, height: axis == .vertical ? size : 0)
176+
return layout
177+
}
178+
179+
open func replace(view: T, at index: Int) {
180+
self.view(at: index)?.removeFromSuperview()
181+
scrollView.addSubview(view)
182+
frameLayout.frameLayout(at: index)?.targetView = view
183+
setNeedsLayout()
184+
}
185+
186+
open func removeView(at index: Int) {
187+
frameLayout.removeFrameLayout(at: index, autoRemoveTargetView: true)
188+
setNeedsLayout()
189+
}
190+
191+
open func removeAll() {
192+
views = []
193+
}
194+
195+
// MARK: -
196+
197+
fileprivate func updateLayout() {
198+
if views.isEmpty {
199+
frameLayout.enumerate({ (layout, index, stop) in
200+
layout.targetView?.removeFromSuperview()
201+
})
202+
203+
frameLayout.removeAll(autoRemoveTargetView: true)
204+
}
205+
else {
206+
let total = views.count
207+
208+
if frameLayout.frameLayouts.count > total {
209+
frameLayout.enumerate({ (layout, index, stop) in
210+
if Int(index) >= Int(total) {
211+
layout.targetView?.removeFromSuperview()
212+
}
213+
})
214+
}
215+
216+
frameLayout.numberOfFrameLayouts = total
217+
218+
frameLayout.enumerate({ (layout, idx, stop) in
219+
let view = views[idx]
220+
scrollView.addSubview(view)
221+
layout.targetView = view
222+
})
223+
}
224+
225+
setNeedsLayout()
226+
}
227+
228+
}

0 commit comments

Comments
 (0)