Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions Sources/SwiftUISupportLayout/Anchoring.swift
Original file line number Diff line number Diff line change
@@ -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
244 changes: 109 additions & 135 deletions Sources/SwiftUISupportLayout/RelativeView.swift
Original file line number Diff line number Diff line change
@@ -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<Content: View>: 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)
}
Loading