Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Pin to the top & bottom of a centered element

Tags:

ios

swift

swiftui

Using SwiftUI, I am trying to center a View on the screen and then give it a header and/or footer of variable heights.

Using constraints it would look something like this:

let view = ...
let header = ...
let footer = ...

view.centerInParent()
header.pinBottomToTop(of: view)
footer.pinTopToBottom(of: view)

This way, the view would always be centered on the screen, regardless of the size of the header and footer.

I cannot figure out how to accomplish this with SwiftUI. Using any type of HStack or VStack means the sizes of the header and footer push around the view. I would like to avoid hardcoding any heights since the center view may vary in size as well.

Any ideas? New to SwiftUI so advice is appreciated!

like image 586
Josh Avatar asked Oct 16 '22 08:10

Josh


1 Answers

If I correctly understood your goal (because, as @nayem commented, at first time seems I missed), the following approach should be helpful.

SwiftUI header&footer

Code snapshot:

extension VerticalAlignment {
   private enum CenteredMiddleView: AlignmentID {
      static func defaultValue(in dimensions: ViewDimensions) -> CGFloat {
         return dimensions[VerticalAlignment.center]
      }
   }

    static let centeredMiddleView = VerticalAlignment(CenteredMiddleView.self)
}

extension Alignment {
    static let centeredView = Alignment(horizontal: HorizontalAlignment.center, 
                          vertical: VerticalAlignment.centeredMiddleView)
}

struct TestHeaderFooter: View {
    var body: some View {
        ZStack(alignment: .centeredView) {
            Rectangle().fill(Color.clear) // !! Extends ZStack to full screen
            VStack {
                Header()
                Text("I'm on center")
                    .alignmentGuide(.centeredMiddleView) { 
                         $0[VerticalAlignment.center]
                    }
                Footer()
            }
        }
//        .edgesIgnoringSafeArea(.top) // uncomment if needed
    }
}

struct Header: View {
    var body: some View {
        Rectangle()
            .fill(Color.blue)
            .frame(height: 40)
    }
}

struct Footer: View {
    var body: some View {
        Rectangle()
            .fill(Color.green)
            .frame(height: 200)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        TestHeaderFooter()
    }
}
like image 80
Asperi Avatar answered Oct 21 '22 02:10

Asperi