diff --git a/Sources/SwiftUISupportLayout/Anchoring.swift b/Sources/SwiftUISupportLayout/Anchoring.swift new file mode 100644 index 0000000000..7b8874a1f4 --- /dev/null +++ b/Sources/SwiftUISupportLayout/Anchoring.swift @@ -0,0 +1,33 @@ +import SwiftUI + +#if DEBUG +// still in development + +#Preview("Using Aligment guide") { + + Rectangle() + .frame(width: 50, height: 50) + .anchoring { + Circle() + .fill(.blue) + } + .background(Color.purple) +} + +extension View { + + internal func anchoring(@ViewBuilder content: () -> some View) -> some View { + overlay(alignment: .topTrailing) { + content() + .alignmentGuide(.top) { d in + d[.top] + d.height / 2 + } + .alignmentGuide(.trailing) { d in + d[.trailing] - d.width / 2 + } + } + } + +} + +#endif diff --git a/Sources/SwiftUISupportLayout/RelativeView.swift b/Sources/SwiftUISupportLayout/RelativeView.swift index 97d2db8c66..a72583c804 100644 --- a/Sources/SwiftUISupportLayout/RelativeView.swift +++ b/Sources/SwiftUISupportLayout/RelativeView.swift @@ -1,169 +1,143 @@ import SwiftUI -public enum RelativeHorizontalPosition { - case left - case center - case right -} - -public enum RelativeVerticalPosition { - case top - case center - case bottom -} - -/// A container view that places the content in the specified position. -/// A useful case will be placing the content on the corner of the parent view. -@available(*, deprecated, message: "Use modifier instead") -public struct RelativeView: View { - - public let content: Content - public let vertical: RelativeVerticalPosition - public let horizontal: RelativeHorizontalPosition - - public init( - vertical: RelativeVerticalPosition, - horizontal: RelativeHorizontalPosition, - @ViewBuilder content: () -> Content - ) { - self.vertical = vertical - self.horizontal = horizontal - self.content = content() - } - - public var body: some View { - - let horizontalContent: some View = HStack { - switch horizontal { - case .left: - content - Spacer(minLength: 0) - case .center: - content - case .right: - Spacer(minLength: 0) - content - } - } - - VStack { - switch vertical { - case .top: - horizontalContent - Spacer(minLength: 0) - case .center: - horizontalContent - case .bottom: - Spacer(minLength: 0) - horizontalContent - } - } - - } -} - -/// like align-self -public struct RelativeLayoutModifier: ViewModifier { +/// deprecated +public struct RelativeLayoutModifier { public enum HorizontalPosition { case leading + @available(*, unavailable) case center case trailing } public enum VerticalPosition { case top + @available(*, unavailable) case center case bottom } - public let vertical: VerticalPosition - public let horizontal: HorizontalPosition +} - public init( - vertical: VerticalPosition, - horizontal: HorizontalPosition - ) { - self.vertical = vertical - self.horizontal = horizontal - } +extension View { - public func body(content: Content) -> some View { - let horizontalContent: some View = HStack { + /** + * Lays out the view and positions it within the layout bounds according to vertical and horizontal positional specifiers. + * Can position the child at any of the 4 corners, or the middle of any of the 4 edges, as well as the center - similar to "9-part" image areas. + */ + @available(*, deprecated, message: "use relative(alignment: )") + public func relative( + vertical: RelativeLayoutModifier.VerticalPosition, + horizontal: RelativeLayoutModifier.HorizontalPosition + ) -> some View { + + return self.relative(alignment: .init( + horizontal: { + switch horizontal { + case .center: + return .center + case .leading: + return .leading + case .trailing: + return .trailing + } + }(), + vertical: { + switch vertical { + case .center: + return .center + case .top: + return .top + case .bottom: + return .bottom + } + }() + ) + ) + } + + @available(*, deprecated, message: "use relative(alignment: )") + public func relative( + horizontal: RelativeLayoutModifier.HorizontalPosition + ) -> some View { + + return self.relative(horizontalAlignment: { switch horizontal { - case .leading: - content - Spacer(minLength: 0) case .center: - content + return .center + case .leading: + return .leading case .trailing: - Spacer(minLength: 0) - content + return .trailing } - } - - VStack { + }() + ) + } + + @available(*, deprecated, message: "use relative(alignment: )") + public func relative( + vertical: RelativeLayoutModifier.VerticalPosition + ) -> some View { + + return self.relative(verticalAlignment: { switch vertical { - case .top: - horizontalContent - Spacer(minLength: 0) case .center: - horizontalContent + return .center + case .top: + return .top case .bottom: - Spacer(minLength: 0) - horizontalContent - } - } + return .bottom + } + }() + ) } - -} - -extension View { - - /** - * Lays out the view and positions it within the layout bounds according to vertical and horizontal positional specifiers. - * Can position the child at any of the 4 corners, or the middle of any of the 4 edges, as well as the center - similar to "9-part" image areas. - */ + public func relative( - vertical: RelativeLayoutModifier.VerticalPosition = .center, - horizontal: RelativeLayoutModifier.HorizontalPosition = .center - ) -> some View { - self.modifier(RelativeLayoutModifier(vertical: vertical, horizontal: horizontal)) + alignment: Alignment + ) -> some View { + self.frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: alignment + ) } - + + public func relative( + horizontalAlignment: HorizontalAlignment + ) -> some View { + self.frame(maxWidth: .infinity, alignment: .init(horizontal: horizontalAlignment, vertical: .center)) + } + + public func relative( + verticalAlignment: VerticalAlignment + ) -> some View { + self.frame(maxHeight: .infinity, alignment: .init(horizontal: .center, vertical: verticalAlignment)) + } + + public func relative( + horizontalAlignment: HorizontalAlignment, + verticalAlignment: VerticalAlignment + ) -> some View { + self.frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .init(horizontal: horizontalAlignment, vertical: verticalAlignment) + ) + } + } -enum Preview_AnchorView: PreviewProvider { - - static var previews: some View { +#Preview { + HStack(alignment: .top) { + Rectangle() - .frame(width: 50, height: 50) - .overlay( - RelativeView(vertical: .top, horizontal: .right) { - Circle() - .foregroundColor(.red) - .frame(width: 20, height: 20) - } - .offset(x: 10, y: -10) - ) - + .frame(width: 100, height: 100) + Rectangle() .frame(width: 50, height: 50) - .overlay( - Circle() - .foregroundColor(.red) - .frame(width: 20, height: 20) - .relative(vertical: .top, horizontal: .trailing) - .offset(x: 10, y: -10) - ) - - HStack { - Text("A") - Text("B") - Text("C") - } - .environment(\.layoutDirection, .rightToLeft) - - } + .foregroundColor(.red) + .relative(verticalAlignment: .center) + } + .background(Color.green) }