Search code examples
viewswiftuiios13

SwiftUI: How to align view to HStack's subview?


I want to align the circle to the TileView "1"'s center at top left. Is there any other like centre constraint of UIView?

enter image description here

struct BoardView: View {
    var body: some View {
        ZStack {
            VStack {
                HStack {
                    TileView(number: 1)
                    TileView(number: 2)
                }
                HStack {
                    TileView(number: 3)
                    TileView(number: 4)
                }
            }
            Circle()
                .frame(width: 30, height: 30)
                .foregroundColor(Color.red.opacity(0.8))

        }
    }
}

Solution

  • Here is possible approach using custom alignment guides

    SwiftUI center dependent shapes

    extension VerticalAlignment {
       private enum VCenterAlignment: AlignmentID {
          static func defaultValue(in dimensions: ViewDimensions) -> CGFloat {
             return dimensions[VerticalAlignment.center]
          }
       }
       static let vCenterred = VerticalAlignment(VCenterAlignment.self)
    }
    
    extension HorizontalAlignment {
       private enum HCenterAlignment: AlignmentID {
          static func defaultValue(in dimensions: ViewDimensions) -> CGFloat {
             return dimensions[HorizontalAlignment.center]
          }
       }
       static let hCenterred = HorizontalAlignment(HCenterAlignment.self)
    }
    
    struct BoardView: View {
        var body: some View {
            ZStack(alignment: Alignment(horizontal: .hCenterred, vertical: .vCenterred)) {
                VStack {
                    HStack {
                        TileView(number: 1)
                            .alignmentGuide(.vCenterred) { $0[VerticalAlignment.center] }
                            .alignmentGuide(.hCenterred) { $0[HorizontalAlignment.center] }
                        TileView(number: 2)
                    }
                    HStack {
                        TileView(number: 3)
                        TileView(number: 4)
                    }
                }
                Circle()
                    .frame(width: 30, height: 30)
                    .foregroundColor(Color.red.opacity(0.8))
                    .alignmentGuide(.vCenterred) { $0[VerticalAlignment.center] }
                    .alignmentGuide(.hCenterred) { $0[HorizontalAlignment.center] }
    
            }
        }
    }
    

    Test module on GitHub