0

As I'm learning SwiftUI in the context of building a WatchOS application, I'm trying to achieve something that seems easy but haven't figured out yet.

Looking at this screenshot I would like to have the text label ("Page 2") being displayed in the vertical center of the tabview's page instead of the bottom.

enter image description here

This is the code for my main content view:

struct ContentView: View {    
    var body: some View {
        VStack {
            PageView()
            Divider()
            Text("First steps are hard")
                .padding()
        }
    }
}

And this is how I implemented the page view:

struct PageView: View {
    @State private var selection = 1

    var body: some View {
        TabView(selection: $selection) {
            Text("Page 1")
                .tag(0)
                .background(Color.yellow)
            Text("Page 2")
                .tag(1)
                .background(Color.red)
            Text("Page 3")
                .tag(2)
                .background(Color.green)
        }
        .border(Color.blue)
    }
}

I've tried setting different alignment options on the VStack as well as setting padding and frames modifier directly on the label. I've also tried embedding PageView in another VStack but nothing really helped so far.

Thanks for your time and help!

MrBr
  • 1,884
  • 2
  • 24
  • 38

1 Answers1

2

If you use GeometryReader to measure the area only inside the individual tab View you can cut its .frame width and height in half. I extracted out your Text("Page 2") to demonstrate.

struct PageView: View {
    @State private var selection = 1
    
    var body: some View {
        TabView(selection: $selection) {
            Text("Page 1")
                .tag(0)
                .background(Color.yellow)
            PageTwo()
                .tag(1)
            Text("Page 3")
                .tag(2)
                .background(Color.green)
        }
        .border(Color.blue)
    }
}

struct PageTwo: View {
    var body: some View {
        GeometryReader(content: { geometry in
            Text("Page 2")
                .background(Color.red)
                .frame(width: geometry.size.width, height: geometry.size.height / 2)
        })
    }
}
Dan O'Leary
  • 916
  • 9
  • 20
  • Nice! That seems to work. I didn't know about `GeometryReader` but seems to be quite an important object for frame layouts. Thank you so much! – MrBr Jun 23 '21 at 13:17
  • 1
    I'm glad I was able to help. And I see I misspoke in my answer by saying you can "cut the width" in half when I didn't actually do that. In this case `.frame` is only reading the width value itself but taking half the height. `GeometryReader` can get a little unwieldy but it's very powerful for fine-tuning layout when you need it. – Dan O'Leary Jun 23 '21 at 13:59