Skip to content

Commit

Permalink
Use frame modifier inside relative modifier (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
muukii authored Oct 23, 2024
1 parent 6e46b93 commit 3a627d2
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 135 deletions.
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)
}

0 comments on commit 3a627d2

Please sign in to comment.