@@ -27,29 +27,50 @@ public enum LayoutSystem {
27
27
}
28
28
}
29
29
30
+ /// - Parameter inheritStackLayoutParticipation: If `true`, the stack layout
31
+ /// will have ``ViewSize/participateInStackLayoutsWhenEmpty`` set to `true`
32
+ /// if all of its children have it set to true. This allows views such as
33
+ /// ``Group`` to avoid changing stack layout participation (since ``Group``
34
+ /// is meant to appear completely invisible to the layout system).
30
35
public static func updateStackLayout< Backend: AppBackend > (
31
36
container: Backend . Widget ,
32
37
children: [ LayoutableChild ] ,
33
38
proposedSize: SIMD2 < Int > ,
34
39
environment: Environment ,
35
40
backend: Backend ,
36
- dryRun: Bool
41
+ dryRun: Bool ,
42
+ inheritStackLayoutParticipation: Bool = false
37
43
) -> ViewSize {
38
44
let spacing = environment. layoutSpacing
39
45
let alignment = environment. layoutAlignment
40
46
let orientation = environment. layoutOrientation
41
- let totalSpacing = ( children. count - 1 ) * spacing
42
-
43
- var spaceUsedAlongStackAxis = 0
44
- var childrenRemaining = children. count
45
47
46
48
var renderedChildren = [ ViewSize] (
47
49
repeating: . empty,
48
50
count: children. count
49
51
)
50
52
51
- // My thanks go to this great article for investigating and explaining how SwiftUI determines
52
- // child view 'flexibility': https://www.objc.io/blog/2020/11/10/hstacks-child-ordering/
53
+ // Figure out which views to treat as hidden. This could be the cause
54
+ // of issues if a view has some threshold at which it suddenly becomes
55
+ // invisible.
56
+ var isHidden = [ Bool] ( repeating: false , count: children. count)
57
+ for (i, child) in children. enumerated ( ) {
58
+ let size = child. computeSize (
59
+ proposedSize: proposedSize,
60
+ environment: environment
61
+ )
62
+ isHidden [ i] =
63
+ size. size == . zero
64
+ && !size. participateInStackLayoutsWhenEmpty
65
+ }
66
+
67
+ // My thanks go to this great article for investigating and explaining
68
+ // how SwiftUI determines child view 'flexibility':
69
+ // https://www.objc.io/blog/2020/11/10/hstacks-child-ordering/
70
+ let visibleChildrenCount = isHidden. count { hidden in
71
+ !hidden
72
+ }
73
+ let totalSpacing = ( visibleChildrenCount - 1 ) * spacing
53
74
let proposedSizeWithoutSpacing = SIMD2 (
54
75
proposedSize. x - ( orientation == . horizontal ? totalSpacing : 0 ) ,
55
76
proposedSize. y - ( orientation == . vertical ? totalSpacing : 0 )
@@ -66,11 +87,40 @@ public enum LayoutSystem {
66
87
size. maximumHeight - Double( size. minimumHeight)
67
88
}
68
89
}
69
- let sortedChildren = zip ( children. enumerated ( ) , flexibilities) . sorted { first, second in
70
- first. 1 <= second. 1
71
- } . map ( \. 0 )
90
+ let sortedChildren = zip ( children. enumerated ( ) , flexibilities)
91
+ . sorted { first, second in
92
+ first. 1 <= second. 1
93
+ }
94
+ . map ( \. 0 )
72
95
96
+ var spaceUsedAlongStackAxis = 0
97
+ var childrenRemaining = visibleChildrenCount
73
98
for (index, child) in sortedChildren {
99
+ // No need to render visible children.
100
+ if isHidden [ index] {
101
+ // Update child in case it has just changed from visible to hidden,
102
+ // and to make sure that the view is still hidden (if it's not then
103
+ // it's a bug with either the view or the layout system).
104
+ let size = child. update (
105
+ proposedSize: . zero,
106
+ environment: environment,
107
+ dryRun: dryRun
108
+ )
109
+ if size. size != . zero || size. participateInStackLayoutsWhenEmpty {
110
+ print ( " warning: Hidden view became visible on second update. Layout may break. " )
111
+ }
112
+ renderedChildren [ index] = ViewSize (
113
+ size: . zero,
114
+ idealSize: . zero,
115
+ minimumWidth: 0 ,
116
+ minimumHeight: 0 ,
117
+ maximumWidth: 0 ,
118
+ maximumHeight: 0 ,
119
+ participateInStackLayoutsWhenEmpty: false
120
+ )
121
+ continue
122
+ }
123
+
74
124
let proposedWidth : Double
75
125
let proposedHeight : Double
76
126
switch orientation {
@@ -149,6 +199,13 @@ public enum LayoutSystem {
149
199
var x = 0
150
200
var y = 0
151
201
for (index, childSize) in renderedChildren. enumerated ( ) {
202
+ // Avoid the whole iteration if the child is hidden. If there
203
+ // are weird positioning issues for views that do strange things
204
+ // then this could be the cause.
205
+ if isHidden [ index] {
206
+ continue
207
+ }
208
+
152
209
// Compute alignment
153
210
switch ( orientation, alignment) {
154
211
case ( . vertical, . leading) :
@@ -182,7 +239,10 @@ public enum LayoutSystem {
182
239
minimumWidth: minimumWidth,
183
240
minimumHeight: minimumHeight,
184
241
maximumWidth: maximumWidth,
185
- maximumHeight: maximumHeight
242
+ maximumHeight: maximumHeight,
243
+ participateInStackLayoutsWhenEmpty:
244
+ inheritStackLayoutParticipation
245
+ && isHidden. allSatisfy { $0 }
186
246
)
187
247
}
188
248
}
0 commit comments