I have an iPhone app which I have configured to also run on an iPad. It works well on both iPhone and iPad, except for the fact that the TabView "tab" items are rendered aestetically differently on the iPad vs the iPhone. I would like to make the iPad tab look the same as on the iPhone but I can't seem to figure out how to do that! Any help would be appreciated..!
Using Xcode 14.3.1
Target OS: iOS 16.2
Deployment info on Xcode:
My TabView code looks like this:
struct ContentView: View {
@EnvironmentObject var BLEinfo: BLEdata
// let timer = Timer.publish (every: 0.8, on: .current, in: .common).autoconnect()
var body: some View {
HStack {
if UIDevice().model == "iPad" && !self.BLEinfo.iPadWiderView {
Spacer().background(.black)
}
TabView(selection: self.$BLEinfo.tabSelected) {
VStack(spacing: 0) {
configTabView()
}
.tabItem {
VStack(spacing: 0) {
Image(systemName: "rectangle.compress.vertical")
.font(Font.system(.title ))
Text("Config. Meter")
}
} .tag(0)
VStack(spacing: 0) {
settingsTabView()
statusLineView()
}
.tabItem {
VStack(spacing: 0) {
Image(systemName: "gear.badge.questionmark")
.font(Font.system(.title ))
Text("Settings & About")
}
} .tag(1)
VStack(spacing: 0) {
connectTabView()
statusLineView()
// Spacer()
}
.tabItem {
VStack(spacing: 0) {
Image(systemName: "dot.radiowaves.left.and.right" )
.font(Font.system(.title ))
Text("Connect Meter")
}
} .tag(2)
VStack(spacing: 0) {
readMeterTabView()
statusLineView()
}
.tabItem {
// Label("Read Meter", systemImage: "speedometer")
VStack(spacing: 0) {
Image(systemName: "speedometer")
.font(Font.system(.title ))
Text("Read Meter")
}
} .tag(3)
}.font(.system(size: CGFloat(self.BLEinfo.nonDynamicUIfontSize)))
.accentColor(.gray)
}.background(Color.init(red: 30/255, green: 30/255, blue: 30/255))
}
}
On an iPhone it renders like this (screenshot of bottom half of iPhone (portrait) screen:
On an iPad it renders like this (screenshot of bottom half of iPad (portrait) screen:
Note how the iPad rendering of the TabItems basically ignores the "VStack" for each TabItem (so it renders the whole tabItem area as an "HStack".
How do I get the same "look" on an iPad? In other words the "Text" of the TabItem needs to be placed BELOW the "image" of the TabItem?
Edit: I have already tried to remove the "VStack" from each "tabItem". That makes no difference on both iPhone & iPad.
Also tried to use the shorter/newer "label" format for the tabItems, so using:
Label("Read Meter", systemImage: "speedometer")
Also has no effect on either device!
Thanks!
According to this post (which is about the same problem but for UIKit), one way to do this is to override the horizontal size class to .compact
. I'm not sure if this is guaranteed to work in future versions, because the tab items displaying horizontally is by-design (See this particular answer). You might want to create your own tab bar instead.
You can override the size class in SwiftUI by modifying the TabView
with:
.environment(\.horizontalSizeClass, .compact)
Note that this would also affect the views in each tab, if they depend on the horizontal size class. To avoid that, get what the size class should have been using an @Environment
and pass that to the tabs.
Here's a rough sketch:
@Environment(\.horizontalSizeClass) var oldSizeClass
var body: some View {
TabView {
SomeView()
.tabItem {
Label(...)
}
.environment(\.horizontalSizeClass, oldSizeClass)
AnotherView()
.tabItem {
Label(...)
}
.environment(\.horizontalSizeClass, oldSizeClass)
}.environment(\.horizontalSizeClass, .compact)
}