Skip to content

Commit fbd0e4d

Browse files
committed
Bugfix and improvement
1 parent 631933c commit fbd0e4d

11 files changed

Lines changed: 235 additions & 164 deletions

Demo/Demo/HVStackWrapperViewDemoViewController.swift

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,28 @@ class HVStackWrapperViewDemoViewController: UIViewController {
140140
// Do any additional setup after loading the view.
141141

142142

143-
let textLayer = CATextLayer()
144-
textLayer.string = "This is CATextLayer in VStackLayerContainerView"
145-
textLayer.fontSize = 12
146-
textLayer.foregroundColor = UIColor.black.cgColor
147-
textLayer.contentsScale = UIScreen.main.scale
143+
func makeTextLayer(title: String) -> CATextLayer {
144+
let textLayer = CATextLayer()
145+
textLayer.string = title
146+
textLayer.fontSize = 14
147+
textLayer.foregroundColor = UIColor.black.cgColor
148+
textLayer.contentsScale = UIScreen.main.scale
149+
return textLayer
150+
}
148151

149152
content.addContent {
150-
VStackLayerContainerView {
153+
VStackLayerContainerView(distribution: .fillWidth(spacing: 0), padding: UIEdgeInsets(top: 10, left: 14, bottom: 10, right: 14)) {
154+
Spacer(length: 20)
155+
makeTextLayer(title: "This is CATextLayer in VStackLayerContainerView")
156+
makeTextLayer(title: "1This is CATextLayer in VStackLayerContainerView1")
157+
}
158+
159+
HStackLayerContainerView(padding: UIEdgeInsets(top: 10, left: 14, bottom: 10, right: 14)) {
151160
Spacer(length: 20)
152-
textLayer
161+
162+
makeTextLayer(title: "Nickname")
163+
Spacer()
164+
makeTextLayer(title: "UserId")
153165
}
154166
}
155167
content.sizeToFit()

Sources/StackKit/HStackView.swift

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,6 @@ open class HStackView: UIView, StackView {
6767
}
6868
}
6969

70-
open var effectiveSubviews: [UIView] {
71-
subviews.filter { $0._isEffectiveView }
72-
}
73-
7470
public var contentSize: CGSize {
7571
let h = effectiveSubviews.map({ $0.frame }).reduce(CGRect.zero) { result, rect in
7672
result.union(rect)
@@ -91,11 +87,7 @@ open class HStackView: UIView, StackView {
9187
}
9288
}
9389

94-
open override func layoutSubviews() {
95-
super.layoutSubviews()
96-
97-
tryResizeStackView()
98-
90+
private func makeSubviewsAlignment() {
9991
switch alignment {
10092
case .top:
10193
effectiveSubviews.forEach { $0.frame.origin.y = _stackContentRect.minY }
@@ -104,6 +96,14 @@ open class HStackView: UIView, StackView {
10496
case .bottom:
10597
effectiveSubviews.forEach { $0.frame.origin.y = _stackContentRect.maxY - $0.frame.height }
10698
}
99+
}
100+
101+
open override func layoutSubviews() {
102+
super.layoutSubviews()
103+
104+
tryResizeStackView()
105+
106+
makeSubviewsAlignment()
107107

108108
switch distribution {
109109
case .spacing(let spacing):
@@ -180,7 +180,7 @@ extension HStackView {
180180
private func makeSpacing(_ spacing: CGFloat) {
181181
for (index, subview) in effectiveSubviews.enumerated() {
182182
if index == 0 {
183-
subview.frame.origin.x = _stackContentRect.minX
183+
subview.frame.origin.x = paddingLeft
184184
} else {
185185
let previousView = effectiveSubviews[index - 1]
186186
if (previousView as? SpacerView) != nil || (subview as? SpacerView) != nil { // spacer and view no spacing
@@ -197,19 +197,18 @@ extension HStackView {
197197
frame.size.height = contentSize.height
198198
}
199199
for subview in effectiveSubviews {
200-
let oldHeight = subview.frame.height
201200
subview.frame.size.height = _stackContentWidth
202201

203202
// fix #https://github.com/iWECon/StackKit/issues/21
204203
guard alignment == .center else {
205204
continue
206205
}
207-
subview.frame.origin.y -= (_stackContentWidth - oldHeight) / 2
206+
subview.center.y = _stackContentRect.midY
208207
}
209208
}
210209

211210
private func fillWidth() {
212-
let maxW = frame.width - lengthOfAllFixedLengthSpacer() - dividerSpecifyLength()
211+
let maxW = frame.width - lengthOfAllFixedLengthSpacer() - lengthOfAllFixedLengthDivider()
213212
var w = (maxW) / CGFloat(viewsWithoutSpacerAndDivider().count)
214213

215214
let unspacersView = viewsWithoutSpacerAndDivider()
@@ -223,12 +222,6 @@ extension HStackView {
223222
// MARK: Divider
224223
extension HStackView {
225224

226-
private func dividerSpecifyLength() -> CGFloat {
227-
dividerViews()
228-
.map({ $0.thickness })
229-
.reduce(0, +)
230-
}
231-
232225
private func fillDivider() {
233226
let maxHeight = effectiveSubviews.filter({ ($0 as? DividerView) == nil }).map({ $0.frame.size.height }).max() ?? frame.height
234227
for divider in effectiveSubviews.compactMap({ $0 as? DividerView }) {
@@ -291,7 +284,7 @@ extension HStackView {
291284

292285
// 非 spacerView 的所有宽度
293286
let unspacerViewsMaxWidth = unspacerViewsWidth + unspacerViewsSpacing
294-
let spacersWidth = (frame.width - unspacerViewsMaxWidth - self.lengthOfAllFixedLengthSpacer())
287+
let spacersWidth = (_stackContentWidth - unspacerViewsMaxWidth - self.lengthOfAllFixedLengthSpacer())
295288
let spacerWidth = spacersWidth / CGFloat(self.dynamicSpacerViews().count)
296289

297290
let spacerViews = self.spacerViews()

Sources/StackKit/Layer+LayerWraperView/HStackLayer.swift

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import UIKit
22

3-
open class HStackLayer: CALayer, _StackLayerProvider {
3+
open class HStackLayer: CALayer, StackLayer {
44

55
public var alignment: HStackAlignment = .center
66
public var distribution: HStackDistribution = .autoSpacing
7+
public var padding: UIEdgeInsets = .zero
78

89
public required override init() {
910
super.init()
@@ -19,13 +20,15 @@ open class HStackLayer: CALayer, _StackLayerProvider {
1920

2021
public required init(
2122
alignment: HStackAlignment = .center,
22-
distribution: HStackDistribution = .autoSpacing,
23+
distribution: HStackDistribution = .spacing(2),
24+
padding: UIEdgeInsets = .zero,
2325
@_StackKitHStackLayerContentResultBuilder content: () -> [CALayer] = { [] }
2426
) {
2527
super.init()
2628

2729
self.alignment = alignment
2830
self.distribution = distribution
31+
self.padding = padding
2932

3033
for l in content() {
3134
addSublayer(l)
@@ -46,9 +49,13 @@ open class HStackLayer: CALayer, _StackLayerProvider {
4649
}
4750

4851
public var contentSize: CGSize {
49-
effectiveSublayers.map({ $0.frame }).reduce(CGRect.zero) { result, rect in
52+
let h = effectiveSublayers.map({ $0.frame }).reduce(CGRect.zero) { result, rect in
5053
result.union(rect)
51-
}.size
54+
}.width
55+
let w = effectiveSublayers.map({ $0.bounds }).reduce(CGRect.zero) { result, rect in
56+
result.union(rect)
57+
}.height
58+
return CGSize(width: h + paddingRight, height: w + paddingVertically)
5259
}
5360

5461
open override func preferredFrameSize() -> CGSize {
@@ -63,19 +70,23 @@ open class HStackLayer: CALayer, _StackLayerProvider {
6370
}
6471
}
6572

66-
public override func layoutSublayers() {
67-
super.layoutSublayers()
68-
69-
refreshSublayers()
70-
73+
private func makeSublayersAlignment() {
7174
switch alignment {
7275
case .top:
73-
effectiveSublayers.forEach { $0.frame.origin.y = 0 }
76+
effectiveSublayers.forEach { $0.frame.origin.y = _stackContentRect.minY }
7477
case .center:
75-
effectiveSublayers.forEach { $0.position.y = frame.height / 2 }
78+
effectiveSublayers.forEach { $0.position.y = _stackContentRect.midY }
7679
case .bottom:
77-
effectiveSublayers.forEach { $0.frame.origin.y = frame.height - $0.frame.height }
80+
effectiveSublayers.forEach { $0.frame.origin.y = _stackContentRect.maxY - $0.frame.height }
7881
}
82+
}
83+
84+
public override func layoutSublayers() {
85+
super.layoutSublayers()
86+
87+
refreshSublayers()
88+
89+
makeSublayersAlignment()
7990

8091
switch distribution {
8192
case .spacing(let spacing):
@@ -93,12 +104,12 @@ open class HStackLayer: CALayer, _StackLayerProvider {
93104
let spacing = autoSpacing()
94105
makeSpacing(spacing)
95106

96-
case .fillHeight: // autoSpacing and fill height
107+
case .fillHeight(let spacing): // autoSpacing and fill height
97108
fillDivider()
98109
fillSpecifySpacer()
99110
fillSpacer()
100111

101-
let spacing = autoSpacing()
112+
let spacing = spacing ?? autoSpacing()
102113
makeSpacing(spacing)
103114
fillHeight()
104115

@@ -130,7 +141,7 @@ extension HStackLayer {
130141
let unspacerViews = viewsWithoutSpacer()
131142
let spacersCount = spacerLayers().map({ isSpacerBetweenViews($0) }).filter({ $0 }).count
132143
let number = unspacerViews.count - spacersCount - 1
133-
return Swift.max(0, (frame.width - viewsWidth() - spacerSpecifyLength()) / CGFloat(max(1, number)))
144+
return Swift.max(0, (frame.width - viewsWidth() - lengthOfAllFixedLengthSpacer()) / CGFloat(max(1, number)))
134145
}
135146

136147
private func viewsWidth() -> CGFloat {
@@ -140,7 +151,7 @@ extension HStackLayer {
140151
private func makeSpacing(_ spacing: CGFloat) {
141152
for (index, sublayer) in effectiveSublayers.enumerated() {
142153
if index == 0 {
143-
sublayer.frame.origin.x = 0
154+
sublayer.frame.origin.x = paddingLeft
144155
} else {
145156
let previousLayer = effectiveSublayers[index - 1]
146157
if (previousLayer as? SpacerLayer) != nil || (sublayer as? SpacerLayer) != nil {
@@ -154,13 +165,21 @@ extension HStackLayer {
154165
}
155166

156167
private func fillHeight() {
157-
effectiveSublayers.forEach {
158-
$0.frame.size.height = frame.height
168+
if frame.height == 0 {
169+
frame.size.height = contentSize.height
170+
}
171+
for sublayer in effectiveSublayers {
172+
sublayer.frame.size.height = _stackContentWidth
173+
174+
guard alignment == .center else {
175+
continue
176+
}
177+
sublayer.position.y = _stackContentRect.midY
159178
}
160179
}
161180

162181
private func fillWidth() {
163-
let maxW = frame.width - spacerSpecifyLength() - dividerSpecifyLength()
182+
let maxW = frame.width - lengthOfAllFixedLengthSpacer() - lengthOfAllFixedLengthDivier()
164183
var w = (maxW) / CGFloat(viewsWithoutSpacerAndDivider().count)
165184

166185
let unspacersView = viewsWithoutSpacerAndDivider()
@@ -173,12 +192,6 @@ extension HStackLayer {
173192

174193
extension HStackLayer {
175194

176-
private func dividerSpecifyLength() -> CGFloat {
177-
dividerLayers()
178-
.map({ $0.thickness })
179-
.reduce(0, +)
180-
}
181-
182195
private func fillDivider() {
183196
let maxWidth = effectiveSublayers.filter({ ($0 as? DividerLayer) == nil }).map({ $0.frame.size.height }).max() ?? frame.height
184197
for divider in effectiveSublayers.compactMap({ $0 as? DividerLayer }) {
@@ -198,13 +211,6 @@ extension HStackLayer {
198211
// MARK: Spacer
199212
extension HStackLayer {
200213

201-
// 取出固定 length 的 spacer
202-
private func spacerSpecifyLength() -> CGFloat {
203-
spacerLayers()
204-
.map({ $0.setLength })
205-
.reduce(0, +)
206-
}
207-
208214
private func isSpacerBetweenViews(_ spacer: SpacerLayer) -> Bool {
209215
guard let index = effectiveSublayers.firstIndex(of: spacer) else {
210216
return false
@@ -248,7 +254,10 @@ extension HStackLayer {
248254
case .spacing(let spacing):
249255
unspacerViewsSpacing = spacing * CGFloat(unspacerViews.count - betweenInViewsCount - 1) // 正常 spacing 数量: (views.count - 1), spacer 左右的视图没有间距,所以需要再排除在 view 之间的 spacer 数量
250256

251-
case .autoSpacing, .fillHeight:
257+
case .fillHeight(let spacing):
258+
unspacerViewsSpacing = (spacing ?? autoSpacing()) * CGFloat(unspacerViews.count - betweenInViewsCount - 1)
259+
260+
case .autoSpacing:
252261
unspacerViewsSpacing = autoSpacing() * CGFloat(unspacerViews.count - betweenInViewsCount - 1)
253262

254263
case .fill:
@@ -258,7 +267,7 @@ extension HStackLayer {
258267

259268
// 非 spacerView 的所有宽度
260269
let unspacerViewsMaxWidth = unspacerViewsWidth + unspacerViewsSpacing
261-
let spacersWidth = (frame.width - unspacerViewsMaxWidth - self.spacerSpecifyLength())
270+
let spacersWidth = (_stackContentWidth - unspacerViewsMaxWidth - self.lengthOfAllFixedLengthSpacer())
262271
let spacerWidth = spacersWidth / CGFloat(self.dynamicSpacerLayers().count)
263272

264273
let spacerViews = self.spacerLayers()

Sources/StackKit/Layer+LayerWraperView/HStackLayerContainerView.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,25 @@ open class HStackLayerContainerView: UIView {
3131
}
3232
}
3333

34+
open var padding: UIEdgeInsets {
35+
get {
36+
hStackLayer.padding
37+
}
38+
set {
39+
hStackLayer.padding = newValue
40+
}
41+
}
42+
3443
public required init(
3544
alignment: HStackAlignment = .center,
36-
distribution: HStackDistribution = .autoSpacing,
45+
distribution: HStackDistribution = .spacing(2),
46+
padding: UIEdgeInsets = .zero,
3747
@_StackKitHStackLayerContentResultBuilder content: () -> [CALayer] = { [] }
3848
) {
3949
super.init(frame: .zero)
4050
hStackLayer.alignment = alignment
4151
hStackLayer.distribution = distribution
52+
hStackLayer.padding = padding
4253

4354
for v in content() {
4455
hStackLayer.addSublayer(v)

0 commit comments

Comments
 (0)