I am having trouble with app tab view headers
. The app contains four tabs with each tab header containing the tab name with a colored background that may be viewed in either portrait or landscape mode.
The first tab is used for transaction data entry and is different from the other three tabs with a Save button
at the right end of the header and also has a Done button
for description and money keyboards.
In portrait mode all four tabs correctly display the title and background color. In landscape mode, the transaction entry tab displays the title and Save button but there is no background color
. The other three tabs correctly display the titles with background color.
I removed the portrait / landscape logic to see if I have a bug in the landscape logic but there was no change in behavior. I also created this cutdown demo with no change observed in landscape transaction entry tab.
I didn’t include all demo tab views in the code below, but you can copy TotalsTabView and change the name for the missing tabs. Likewise I didn’t include all transaction entry views such as categories, description, and money since they all are simple text views.
Create transaction entry view
struct EntryTabView: View {
enum Field: Hashable {
case ckDsc
case ckAmt
}
@FocusState private var myFocus: Field?
var body: some View {
GeometryReader { g in
VStack {
ZStack (alignment: .top) {
if g.size.height > g.size.width { // portrait?
Color(.green)
.frame(height: g.safeAreaInsets.top * 1.9, alignment: .top)
.ignoresSafeArea()
} else { // landscape
Color(.green)
.frame(height: g.safeAreaInsets.top * 0.14, alignment: .top)
.ignoresSafeArea()
}
HStack {
VStack (alignment: .leading) {
Text("Expense Entry")
.font(.title)
.bold()
.kerning(1.5)
.padding(.leading, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
Spacer()
Button {
myFocus = nil
//self.saveButton() // button pressed
} label: {
Text("Save")
.bold()
.padding(.trailing, 10)
.tint(.blue)
}
// .disabled(moneyS.isEmpty)
}
}
Form {
GetDate()
.padding(.bottom, 10)
GetPaymentType()
.padding(.bottom, 10)
GetCategory()
.padding(.bottom, 10)
GetDescription()
.padding(.bottom, 10)
GetMoney()
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("Done")
{
myFocus = nil
}
}
}
}
}
}
struct ContentView: View {
var body: some View {
NavigationStack {
VStack {
TabView () {
EntryTabView()
.tabItem {
Label("Expense Entry", systemImage: "entry.lever.keypad")
}
.tag(0)
TotalsTabView()
.tabItem {
Label("Totals", systemImage: "t.circle.fill")
}
.tag(1)
HistoryTabView()
.tabItem {
Label("History", systemImage: "clock.arrow.circlepath")
}
.tag(2)
MenuTabView()
.tabItem {
Label("More", systemImage: "ellipsis")
}
.tag(3)
}
}
.tint(.blue)
.symbolRenderingMode(.hierarchical)
.symbolVariant(.fill)
}
}
}
Structure used to create tab view title headers (portrait / landscape and difference
size iPhones
struct DrawTabTitleBox: View {
var g: GeometryProxy
var title: String
var body: some View {
ZStack (alignment: .top) {
if g.size.height > g.size.width { // portrait
if g.size.width < 380 { // mini?
Color(.green)
.frame(height: g.safeAreaInsets.top * 1.9, alignment: .top)
.ignoresSafeArea()
VStack (alignment: .leading) {
Text(title)
.font(.title)
.bold()
.kerning(1.5)
.padding(.leading, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
} else { // pro max
Color(.green)
.frame(height: g.safeAreaInsets.top * 1.65, alignment: .top)
.ignoresSafeArea()
VStack (alignment: .leading) {
Text(title)
.font(.title)
.bold()
.kerning(1.5)
.padding(.leading, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
} else { // landscape
if g.size.width < 720 {
Color(.green)
.ignoresSafeArea()
.frame(height: g.size.height * 0.14)
VStack (alignment: .leading) {
Text(title)
.font(.title)
.bold()
.kerning(1.5)
.padding(.top, 11)
.padding(.leading, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
} else {
Color(.green)
.ignoresSafeArea()
.frame(height: g.size.height * 0.126)
VStack (alignment: .leading) {
Text(title)
.font(.title)
.bold()
.kerning(1.5)
.padding(.top, 11)
.padding(.leading, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
}
}
}
Typical transaction entry dummy code
struct GetDate: View {
var body: some View {
Text("Get Date")
}
}
Method used to create tabview headers except for transaction entry tab
struct TotalsTabView: View {
var body: some View {
GeometryReader { g in
VStack (alignment: .leading, spacing: 0) {
DrawTabTitleBox(g: g, title: "Totals")
Text("Totals View")
.frame(maxWidth: .infinity, alignment: .center)
}
}
}
}