Skip to content

Commit 325e80b

Browse files
committed
Update commitPlacements to handle layoutDirection
1 parent 1ab55d5 commit 325e80b

File tree

2 files changed

+68
-37
lines changed

2 files changed

+68
-37
lines changed

Example/OpenSwiftUIUITests/Layout/Stack/HVStackUITests.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,26 @@ struct HVStackUITests {
164164
.background { Color.black }
165165
}
166166
}
167-
withKnownIssue("layoutPriority is not implemented for HVStack yet") {
167+
withKnownIssue {
168+
openSwiftUIAssertSnapshot(
169+
of: ContentView()
170+
)
171+
}
172+
}
173+
174+
@Test("Verify red and blue should have the same size")
175+
func sameSizeInVStack() {
176+
struct ContentView: View {
177+
var body: some View {
178+
VStack(spacing: 20) {
179+
Color.red
180+
Color.yellow
181+
.frame(width: 10, height: 10)
182+
Color.blue
183+
}
184+
}
185+
}
186+
withKnownIssue {
168187
openSwiftUIAssertSnapshot(
169188
of: ContentView()
170189
)

Sources/OpenSwiftUICore/Layout/Stack/StackLayout.swift

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,6 @@ extension StackLayout {
303303
headerPtr.pointee.resizeChildrenWithTrailingOverflow
304304
}
305305

306-
// FIXME: [Copilot Generated]
307306
/// Commits the final placement of children within bounds.
308307
///
309308
/// - Parameters:
@@ -313,41 +312,54 @@ extension StackLayout {
313312
in bounds: CGRect,
314313
proposedSize: ProposedViewSize
315314
) {
316-
placeChildren(in: proposedSize)
317-
318-
guard !childrenPtr.isEmpty else { return }
319-
320-
// Calculate offsets to center the stack within bounds
321-
let majorOffset = bounds.origin[majorAxis] +
322-
(bounds.size[majorAxis] - stackSize[majorAxis]) / 2
323-
let minorOffset = bounds.origin[minorAxis] +
324-
(bounds.size[minorAxis] - stackSize[minorAxis]) / 2
325-
326-
// Place each child view at its calculated position
327-
for (index, child) in childrenPtr.enumerated() {
328-
let finalOrigin = CGPoint(
329-
child.geometry.origin[majorAxis] + majorOffset,
330-
in: majorAxis,
331-
by: child.geometry.origin[minorAxis] + minorOffset
332-
)
333-
334-
let finalBounds = CGRect(
335-
origin: finalOrigin,
336-
size: child.geometry.dimensions.size.value
337-
)
338-
339-
// Get the child-specific proposed size
340-
let childProposal = ProposedViewSize(
341-
child.geometry.dimensions.size[majorAxis],
342-
in: majorAxis,
343-
by: child.geometry.dimensions.size[minorAxis]
344-
)
345-
346-
proxies[index].place(
347-
at: finalBounds.origin,
348-
anchor: .topLeading,
349-
proposal: childProposal
350-
)
315+
let proposal = proposalWhenPlacing(in: ViewSize(bounds.size, proposal: .init(proposedSize)))
316+
placeChildren(in: proposal)
317+
let layoutDirection = proxies.layoutDirection
318+
if majorAxis == .horizontal {
319+
var currentMajorPosition = layoutDirection == .rightToLeft ? bounds.maxX : bounds.minX
320+
let minorBasePosition = bounds.minY
321+
for (child, proxy) in zip(childrenPtr, proxies) {
322+
let geometry = child.geometry
323+
let frame = geometry.frame
324+
let majorOrigin: CGFloat
325+
if layoutDirection == .rightToLeft {
326+
majorOrigin = currentMajorPosition - child.distanceToPrevious
327+
currentMajorPosition = majorOrigin - frame.width
328+
} else {
329+
majorOrigin = currentMajorPosition + child.distanceToPrevious
330+
currentMajorPosition = majorOrigin + frame.width
331+
}
332+
let finalMajorOrigin = majorOrigin.mappingNaN(to: frame.origin.x)
333+
let finalMinorOrigin = frame.origin.y + minorBasePosition
334+
proxy.place(
335+
in: ViewGeometry(
336+
origin: CGPoint(x: finalMajorOrigin, y: finalMinorOrigin),
337+
dimensions: geometry.dimensions
338+
),
339+
layoutDirection: layoutDirection
340+
)
341+
}
342+
} else {
343+
var currentMajorPosition = bounds.minY
344+
let minorBasePosition = bounds.minX
345+
for (child, proxy) in zip(childrenPtr, proxies) {
346+
let geometry = child.geometry
347+
let frame = geometry.frame
348+
let majorOrigin = currentMajorPosition + child.distanceToPrevious
349+
currentMajorPosition = majorOrigin + frame.height
350+
let finalMajorOrigin = majorOrigin.mappingNaN(to: frame.origin.y)
351+
let minorOrigin = layoutDirection == .rightToLeft
352+
? frame.maxX
353+
: frame.origin.x
354+
let finalMinorOrigin = minorOrigin + minorBasePosition
355+
proxy.place(
356+
in: ViewGeometry(
357+
origin: CGPoint(x: finalMinorOrigin, y: finalMajorOrigin),
358+
dimensions: geometry.dimensions
359+
),
360+
layoutDirection: layoutDirection
361+
)
362+
}
351363
}
352364
}
353365

0 commit comments

Comments
 (0)