Josh
Josh

Reputation: 1718

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

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!

Upvotes: 5

Views: 5187

Answers (3)

Ruchi Makadia
Ruchi Makadia

Reputation: 1083

Here's the code:

struct ContentView: View {
    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .leading) {
                Rectangle()
                .fill(Color.gray)
                .frame(width: geometry.size.width, height: geometry.size.height * 0.1, alignment: .center)
            Text("Center")
                .frame(width: geometry.size.width, height: geometry.size.height * 0.2, alignment: .center)
            Rectangle()
                .fill(Color.gray)
                .frame(width: geometry.size.width, height: geometry.size.height * 0.1, alignment: .center)
            }
        }
    }
}

using GeometryReader you can apply the dynamic size for your views. also here is screenshot for above code

enter image description here

Upvotes: 1

Asperi
Asperi

Reputation: 257693

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()
    }
}

Upvotes: 3

Nirav shekhaliya
Nirav shekhaliya

Reputation: 52

put Spacer() between header view and footer view.

headerview()
Spacer()
footerview()

Upvotes: -1

Related Questions