-
Notifications
You must be signed in to change notification settings - Fork 58
Closed
Description
I implemented a custom layout similar to the original ZStack to help diagnose the issue. It prints the dimensions during sizeThatFits.
struct MyCustomZStack: Layout {
public var alignment: Alignment
@inlinable
public init(alignment: Alignment = .center) {
self.alignment = alignment
}
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
guard !subviews.isEmpty else {
return CGSize.zero
}
let maxPriority =
subviews.lazy
.map { $0.priority }
.max() ?? 0.0
return subviews.lazy
.filter { $0.priority == maxPriority }
.map {
let dimension = $0.dimensions(in: proposal)
print(dimension)
return dimension
}
.reduce(CGSize.zero) { result, dimension in
CGSize(
width: max(result.width, dimension.width),
height: max(result.height, dimension.height)
)
}
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let maxPriority =
subviews.lazy
.map { $0.priority }
.max() ?? 0.0
let alignmentSize = subviews.lazy
.filter { $0.priority == maxPriority }
.map { $0.dimensions(in: ProposedViewSize(bounds.size)) }
.reduce(CGSize(width: -.infinity, height: -.infinity)) { result, dimension in
CGSize(
width: max(result.width, dimension[alignment.horizontal]),
height: max(result.height, dimension[alignment.vertical])
)
}
for subview in subviews {
let dimensions = subview.dimensions(in: ProposedViewSize(bounds.size))
let horizontalAlignmentValue = dimensions[alignment.horizontal]
let verticalAlignmentValue = dimensions[alignment.vertical]
let origin = CGPoint(
x: alignmentSize.width - horizontalAlignmentValue + bounds.origin.x,
y: alignmentSize.height - verticalAlignmentValue + bounds.origin.y
)
subview.place(at: origin, proposal: proposal)
}
}
}Test Case
struct TestExample: View {
@State private var showed = true
var body: some View {
MyCustomZStack {
if showed {
Color.red
.frame(width: 300, height: 300)
}
Color.blue
.frame(width: 200, height: 200)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
first.toggle()
}
}
}
}
}Expected Behavior
SwiftUI Output
ViewDimensions(guideComputer: SwiftUI.LayoutComputer(box: SwiftUI.(unknown context at $1d4dfec58).LayoutEngineBox<SwiftUI.(unknown context at $1d4df00ec).UnaryLayoutEngine<SwiftUI._FrameLayout>>, seed: 0), size: SwiftUI.ViewSize(value: (300.0, 300.0), _proposal: (440.0, 860.0)))
ViewDimensions(guideComputer: SwiftUI.LayoutComputer(box: SwiftUI.(unknown context at $1d4dfec58).LayoutEngineBox<SwiftUI.(unknown context at $1d4df00ec).UnaryLayoutEngine<SwiftUI._FrameLayout>>, seed: 0), size: SwiftUI.ViewSize(value: (200.0, 200.0), _proposal: (440.0, 860.0)))
ViewDimensions(guideComputer: SwiftUI.LayoutComputer(box: SwiftUI.(unknown context at $1d4dfec58).LayoutEngineBox<SwiftUI.(unknown context at $1d4df00ec).UnaryLayoutEngine<SwiftUI._FrameLayout>>, seed: 1), size: SwiftUI.ViewSize(value: (200.0, 200.0), _proposal: (440.0, 860.0)))
ViewDimensions(guideComputer: SwiftUI.LayoutComputer(box: SwiftUI.(unknown context at $1d4dfec58).LayoutEngineBox<SwiftUI.(unknown context at $1d4df00ec).UnaryLayoutEngine<SwiftUI._FrameLayout>>, seed: 1), size: SwiftUI.ViewSize(value: (200.0, 200.0), _proposal: (440.0, 860.0)))
Observed Behavior
OpenSwiftUI Output
ViewDimensions(guideComputer: OpenSwiftUICore.LayoutComputer(box: OpenSwiftUICore.(unknown context at $1054ca2e8).LayoutEngineBox<OpenSwiftUICore.(unknown context at $1054ca7b0).UnaryLayoutEngine<OpenSwiftUICore._FrameLayout>>, seed: 0), size: OpenSwiftUICore.ViewSize(value: (300.0, 300.0), _proposal: (440.0, 821.6666666666667)))
ViewDimensions(guideComputer: OpenSwiftUICore.LayoutComputer(box: OpenSwiftUICore.(unknown context at $1054ca2e8).LayoutEngineBox<OpenSwiftUICore.(unknown context at $1054ca7b0).UnaryLayoutEngine<OpenSwiftUICore._FrameLayout>>, seed: 0), size: OpenSwiftUICore.ViewSize(value: (200.0, 200.0), _proposal: (440.0, 821.6666666666667)))
ViewDimensions(guideComputer: OpenSwiftUICore.LayoutComputer(box: OpenSwiftUICore.(unknown context at $1054ca2e8).LayoutEngineBox<OpenSwiftUICore.(unknown context at $1054ca7b0).UnaryLayoutEngine<OpenSwiftUICore._FrameLayout>>, seed: 1), size: OpenSwiftUICore.ViewSize(value: (200.0, 200.0), _proposal: (440.0, 821.6666666666667)))
ViewDimensions(guideComputer: OpenSwiftUICore.LayoutComputer(box: OpenSwiftUICore.(unknown context at $1054ca2e8).LayoutEngineBox<OpenSwiftUICore.LayoutComputer.DefaultEngine>, seed: 0), size: OpenSwiftUICore.ViewSize(value: (440.0, 821.6666666666667), _proposal: (440.0, 821.6666666666667)))
Related
The layoutComputer will be nil, and use the DefaultEngine.
package struct LayoutProxy: Equatable {
...
package var layoutComputer: LayoutComputer {
guard let layoutComputer = attributes.$layoutComputer else {
return .defaultValue
}
return context[layoutComputer]
}
...
package func dimensions(in proposedSize: _ProposedSize) -> ViewDimensions {
let computer = layoutComputer
return ViewDimensions(
guideComputer: computer,
size: computer.sizeThatFits(proposedSize),
proposal: _ProposedSize(
width: proposedSize.width ?? .nan,
height: proposedSize.height ?? .nan
)
)
}
}Kyle-Ye
Metadata
Metadata
Assignees
Labels
No labels