From cdb5d06e467087bd9da78bcb6379dd3dc063e504 Mon Sep 17 00:00:00 2001 From: Dark-Existed Date: Wed, 17 Sep 2025 19:06:26 +0800 Subject: [PATCH 1/5] Add PositionLayout --- .../Layout/Modifier/PositionLayout.swift | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift diff --git a/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift new file mode 100644 index 000000000..13114b629 --- /dev/null +++ b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift @@ -0,0 +1,80 @@ +public import Foundation + +@_spi(ForOpenSwiftUIOnly) +public import OpenSwiftUICore + +// MARK: - PositionLayout + +@frozen +public struct _PositionLayout: UnaryLayout { + public var position: CGPoint + + @inlinable + public init(position: CGPoint) { + self.position = position + } + + package func sizeThatFits( + in proposal: _ProposedSize, + context: SizeAndSpacingContext, + child: LayoutProxy + ) -> CGSize { + CGSize(proposal) ?? proposal.fixingUnspecifiedDimensions(at: child.size(in: proposal)) + } + + package func spacing(in: SizeAndSpacingContext, child: LayoutProxy) -> Spacing { + if Semantics.StopProjectingAffectedSpacing.isEnabled { + return Spacing() + } + return child.spacing() + } + + package func placement(of: LayoutProxy, in context: PlacementContext) -> _Placement { + _Placement(proposedSize: context.size, anchoring: .center, at: position) + } +} + +extension View { + /// Positions the center of this view at the specified point in its parent's + /// coordinate space. + /// + /// Use the `position(_:)` modifier to place the center of a view at a + /// specific coordinate in the parent view using a + /// to specify the `x` + /// and `y` offset. + /// + /// Text("Position by passing a CGPoint()") + /// .position(CGPoint(x: 175, y: 100)) + /// .border(Color.gray) + /// + /// - Parameter position: The point at which to place the center of this + /// view. + /// + /// - Returns: A view that fixes the center of this view at `position`. + + @inlinable + nonisolated public func position(_ position: CGPoint) -> some View { + modifier(_PositionLayout(position: position)) + } + + /// Positions the center of this view at the specified coordinates in its + /// parent's coordinate space. + /// + /// Use the `position(x:y:)` modifier to place the center of a view at a + /// specific coordinate in the parent view using an `x` and `y` offset. + /// + /// Text("Position by passing the x and y coordinates") + /// .position(x: 175, y: 100) + /// .border(Color.gray) + /// + /// - Parameters: + /// - x: The x-coordinate at which to place the center of this view. + /// - y: The y-coordinate at which to place the center of this view. + /// + /// - Returns: A view that fixes the center of this view at `x` and `y`. + + @inlinable + nonisolated public func position(x: CGFloat = 0, y: CGFloat = 0) -> some View { + position(.init(x: x, y: y)) + } +} From 1b40002bc4c284d11a6e34831e9a5fffe155a283 Mon Sep 17 00:00:00 2001 From: Dark-detsixE Date: Sat, 20 Sep 2025 23:23:50 +0800 Subject: [PATCH 2/5] Add PositionLayoutUITests --- .../Modifier/PositionLayoutUITests.swift | 60 +++++++++++++++++++ .../Layout/Modifier/PositionLayout.swift | 8 +++ 2 files changed, 68 insertions(+) create mode 100644 Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift diff --git a/Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift b/Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift new file mode 100644 index 000000000..b1de8800e --- /dev/null +++ b/Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift @@ -0,0 +1,60 @@ +// +// PositionLayoutUITests.swift +// OpenSwiftUIUITests + +import SnapshotTesting +import Testing + +@MainActor +@Suite(.snapshots(record: .never, diffTool: diffTool)) +struct PositionLayoutUITests { + + @Test + func defaultPosition() { + struct ContentView: View { + var body: some View { + Color.blue + .frame(width: 50, height: 30) + .position() + } + } + openSwiftUIAssertSnapshot(of: ContentView()) + } + + @Test + func specificXAxis() { + struct ContentView: View { + var body: some View { + Color.blue + .frame(width: 50, height: 30) + .position(x: 30) + } + } + openSwiftUIAssertSnapshot(of: ContentView()) + } + + + @Test + func specificYAxis() { + struct ContentView: View { + var body: some View { + Color.blue + .frame(width: 50, height: 30) + .position(y: 40) + } + } + openSwiftUIAssertSnapshot(of: ContentView()) + } + + @Test + func specificPosition() { + struct ContentView: View { + var body: some View { + Color.blue + .frame(width: 50, height: 30) + .position(x: 50, y: 60) + } + } + openSwiftUIAssertSnapshot(of: ContentView()) + } +} diff --git a/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift index 13114b629..9e2af965d 100644 --- a/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift +++ b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift @@ -1,3 +1,11 @@ +// +// PositionLayout.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: Complete +// ID: (SwiftUI) + public import Foundation @_spi(ForOpenSwiftUIOnly) From 47b6393a1507ff7f351769971fadbb51000a638a Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 25 Oct 2025 18:45:36 +0800 Subject: [PATCH 3/5] Update documentation and format --- .../Layout/Modifier/PositionLayout.swift | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift index 9e2af965d..0f05b79cf 100644 --- a/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift +++ b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift @@ -1,18 +1,21 @@ // // PositionLayout.swift -// OpenSwiftUICore +// OpenSwiftUI // // Audited for 6.5.4 // Status: Complete -// ID: (SwiftUI) - -public import Foundation +public import OpenCoreGraphicsShims @_spi(ForOpenSwiftUIOnly) public import OpenSwiftUICore // MARK: - PositionLayout +/// Allows you to redefine center of the child within its coördinate space +/// +/// Child sizing: Respects the child's size +/// Preferred size: CGSize of the child +@available(OpenSwiftUI_v1_0, *) @frozen public struct _PositionLayout: UnaryLayout { public var position: CGPoint @@ -42,13 +45,14 @@ public struct _PositionLayout: UnaryLayout { } } +@available(OpenSwiftUI_v1_0, *) extension View { /// Positions the center of this view at the specified point in its parent's /// coordinate space. /// /// Use the `position(_:)` modifier to place the center of a view at a /// specific coordinate in the parent view using a - /// to specify the `x` + /// [CGPoint](https://developer.apple.com/documentation/coregraphics/cgpoint) to specify the `x` /// and `y` offset. /// /// Text("Position by passing a CGPoint()") @@ -59,7 +63,6 @@ extension View { /// view. /// /// - Returns: A view that fixes the center of this view at `position`. - @inlinable nonisolated public func position(_ position: CGPoint) -> some View { modifier(_PositionLayout(position: position)) @@ -80,9 +83,8 @@ extension View { /// - y: The y-coordinate at which to place the center of this view. /// /// - Returns: A view that fixes the center of this view at `x` and `y`. - @inlinable nonisolated public func position(x: CGFloat = 0, y: CGFloat = 0) -> some View { - position(.init(x: x, y: y)) + position(CGPoint(x: x, y: y)) } } From a7e54aa72c7ae3789a70f82078b840fc17765f70 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 25 Oct 2025 18:51:04 +0800 Subject: [PATCH 4/5] [NFC] Update PositionLayout format --- .../Layout/Modifier/PositionLayout.swift | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift index 0f05b79cf..6cd4953c9 100644 --- a/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift +++ b/Sources/OpenSwiftUI/Layout/Modifier/PositionLayout.swift @@ -25,6 +25,13 @@ public struct _PositionLayout: UnaryLayout { self.position = position } + package func placement( + of: LayoutProxy, + in context: PlacementContext + ) -> _Placement { + _Placement(proposedSize: context.size, anchoring: .center, at: position) + } + package func sizeThatFits( in proposal: _ProposedSize, context: SizeAndSpacingContext, @@ -34,14 +41,10 @@ public struct _PositionLayout: UnaryLayout { } package func spacing(in: SizeAndSpacingContext, child: LayoutProxy) -> Spacing { - if Semantics.StopProjectingAffectedSpacing.isEnabled { - return Spacing() + guard Semantics.StopProjectingAffectedSpacing.isEnabled else { + return child.spacing() } - return child.spacing() - } - - package func placement(of: LayoutProxy, in context: PlacementContext) -> _Placement { - _Placement(proposedSize: context.size, anchoring: .center, at: position) + return Spacing() } } From 1d674127426b3dd2baadf25be2cb39a319fab852 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 25 Oct 2025 18:58:51 +0800 Subject: [PATCH 5/5] Update PositionLayoutUITests --- .../Modifier/PositionLayoutUITests.swift | 57 +++++-------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift b/Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift index b1de8800e..43597f27b 100644 --- a/Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift +++ b/Example/OpenSwiftUIUITests/Layout/Modifier/PositionLayoutUITests.swift @@ -8,51 +8,24 @@ import Testing @MainActor @Suite(.snapshots(record: .never, diffTool: diffTool)) struct PositionLayoutUITests { - - @Test - func defaultPosition() { - struct ContentView: View { - var body: some View { - Color.blue - .frame(width: 50, height: 30) - .position() - } - } - openSwiftUIAssertSnapshot(of: ContentView()) - } - - @Test - func specificXAxis() { - struct ContentView: View { - var body: some View { - Color.blue - .frame(width: 50, height: 30) - .position(x: 30) - } - } - openSwiftUIAssertSnapshot(of: ContentView()) - } - - - @Test - func specificYAxis() { - struct ContentView: View { - var body: some View { - Color.blue - .frame(width: 50, height: 30) - .position(y: 40) - } - } - openSwiftUIAssertSnapshot(of: ContentView()) - } - @Test - func specificPosition() { + func positionInZStack() { struct ContentView: View { var body: some View { - Color.blue - .frame(width: 50, height: 30) - .position(x: 50, y: 60) + ZStack { + Color.red + .frame(width: 50, height: 50) + .position() + Color.green + .frame(width: 50, height: 50) + .position(x: 50) + Color.blue + .frame(width: 50, height: 50) + .position(y: 50) + Color.black + .frame(width: 50, height: 50) + .position(x: 50, y: 50) + }.frame(width: 100, height: 100) } } openSwiftUIAssertSnapshot(of: ContentView())