C.Aglar
C.Aglar

Reputation: 1319

How to calculate Tab Bar height in SwiftUI?

I have a page with a player that has a height of 1/3 of the screen height. Under the channels, there are multiple channels inside a scroll view. I am trying to set the height of the scroll view section exactly from bottom of the player to bottom of the page. I tried to set it to (screen height - (playerheight) - (navigation bar height) - (tabbed bar height)). But the problem is that the tabbed bar height changes from device to device. I tried the following code:

.frame(height: (UIScreen.main.bounds.height) - ((UIScreen.main.bounds.height) * 2/6) - (geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom ) )

But it looks like geometry.safeAreaInsets.bottom does not contain the tabbed bar height. So is there any way to calculate it in SwiftUI or is there any other way to achieve a similar appearance?

I just want to place scrollview that contains the channels exactly between player and tab bar for all screen sizes.

sample design

Upvotes: 4

Views: 9219

Answers (1)

DonMag
DonMag

Reputation: 77452

I'm just starting to look at SwiftUI, but... I'm under the impression GeometryReader should handle this for you.

Give this a try:

struct Tab1View: View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("Top == 1/3 height")
                    .frame(width: geometry.size.width, height: geometry.size.height / 3.0, alignment: .center)
                    .background(Color.init(red: 0.1, green: 0.1, blue: 0.5))
                    .foregroundColor(Color.white)
                    .border(Color.yellow)
                Text("Bottom == 2/3 height")
                    .frame(width: geometry.size.width, height: geometry.size.height * 2.0 / 3.0, alignment: .center)
                    .background(Color.init(red: 0.5, green: 0.1, blue: 0.1))
                    .foregroundColor(Color.white)
                    .border(Color.yellow)
            }
            .frame(width: geometry.size.width,
                   height: geometry.size.height,
                   alignment: .topLeading)
        }
    }

}
struct Tab2View: View {
    var body: some View {
        Color.blue
    }
}

struct MyTabView: View {
    var body: some View {

        TabView {
            //Text("The content of the first view")
            Tab1View()
                .tabItem {
                    Image(systemName: "phone.fill")
                    Text("First Tab")
            }
            //Text("The content of the second view")
            Tab2View()
                .tabItem {
                    Image(systemName: "tv.fill")
                    Text("Second Tab")
            }
        }
    }
}

struct MyTabView_Previews: PreviewProvider {
    static var previews: some View {
        MyTabView()
    }
}

Result:

enter image description here

and, auto-adjusted to TabBar height when rotated:

enter image description here


Edit

After some more investigation, it looks like ScrollView can size itself to fill available space, so we only need to set the height on the top view.

Here's a modified example:

struct MyItemView: View {
    var itemDesc = "Testing"
    var geoWidth: CGFloat = 100
    var body: some View {
            Text("\(self.itemDesc)")
                .foregroundColor(Color.white)
                .padding(16.0)
                .frame(width: self.geoWidth, height: nil, alignment: .leading)
    }
}

struct Tab1View: View {
    var body: some View {
        GeometryReader { geometry in
            VStack(spacing: 0.0) {
                Text("Top == 1/3 height")
                    .frame(width: geometry.size.width, height: geometry.size.height * 1.0 / 3.0, alignment: .center)
                    .background(Color.init(red: 0.1, green: 0.1, blue: 0.5))
                    .foregroundColor(Color.white)
                    .border(Color.yellow)

                ScrollView(.vertical) {
                    VStack(alignment: .leading, spacing: 0) {
                        ForEach((1...20), id: \.self) {
                            MyItemView(itemDesc: "This is item \($0)", geoWidth: geometry.size.width)
                                .background(Color.init(red: 0.5, green: 0.1, blue: 0.1))
                                .border(Color.yellow)
                        }
                    }
                }
                .frame(width: geometry.size.width, height: nil, alignment: .leading)
            }
        }
    }
}
struct Tab2View: View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("Top == 1/3 height")
                    .frame(width: geometry.size.width, height: geometry.size.height * 1.0 / 3.0, alignment: .center)
                    .background(Color.init(red: 0.1, green: 0.1, blue: 0.7))
                    .foregroundColor(Color.white)
                    .border(Color.yellow)
                Text("Bottom == 2/3 height")
                    .frame(width: geometry.size.width, height: geometry.size.height * 2.0 / 3.0, alignment: .center)
                    .background(Color.init(red: 0.2, green: 0.6, blue: 0.1))
                    .foregroundColor(Color.white)
                    .border(Color.yellow)
            }
        }
    }
}
struct MyTabView: View {
    var body: some View {
        TabView {
            Tab1View()
                .tabItem {
                    Image(systemName: "phone.fill")
                    Text("First Tab")
            }
            Tab2View()
                .tabItem {
                    Image(systemName: "tv.fill")
                    Text("Second Tab")
            }
        }
    }
}

struct MyTabView_Previews: PreviewProvider {
    static var previews: some View {
        MyTabView()
    }
}

and, new result:

enter image description here

enter image description here

Upvotes: 3

Related Questions