Im stuck at one more problem.
The first is with the display of the tab view in the other pages.
The second one which I’m facing currently is another problem with my tab view. I changed a bit and did some animation stuff on the tab bar so that it looks fancy and I’m very satisfied with the outcome but unfortunately, it doesn’t switch between the pages.
When i change the value in line 62 from @State **var** selectedTab : Tab = .teams
to for e.g. @State var selectedTab : Tab = .transactions
the tab view button changes and the view also changes, but clicking the button has no effects besides the animation.
Here is the code from my MainTabView:
//
// MainTabView.swift
// Football Tracker
//
// Created by David Laczkovits on 10.03.25.
//
import SwiftUI
enum Tab: Int, Identifiable, CaseIterable, Comparable {
static func < (lhs: Tab, rhs: Tab) -> Bool {
lhs.rawValue < rhs.rawValue
}
case teams, transactions, gameplan, liveticker
internal var id: Int { rawValue }
var icon: String {
switch self {
case .teams:
return "person.3.fill"
case .transactions:
return "dollarsign.circle.fill"
case .gameplan:
return "calendar"
case .liveticker:
return "play.tv.fill"
}
}
var title: String {
switch self {
case .teams:
return "Teams"
case .transactions:
return "Trades"
case .gameplan:
return "Plan"
case .liveticker:
return "Ticker"
}
}
var color: Color {
switch self {
case .teams:
return .teams
case .transactions:
return .transactions
case .gameplan:
return .gameplan
case .liveticker:
return .liveticker
}
}
}
struct MainTabView: View {
@State var selectedTab : Tab = .teams
@Environment(\.openURL) var openURL
@Environment(\.colorScheme) var colorScheme
@State private var askForAttachment = false
@State private var showEmail = false
@State private var langCode = "en"
@State private var email = SupportEmail(toAddress: "support@laczkovits.info",
subject: "Support Email from Football Index App",
messageHeader: "Please describe your issue below")
var body: some View {
GeometryReader { geo in
ZStack {
Image("background")
.resizable()
.opacity(0.5)
.ignoresSafeArea()
VStack {
NavigationStack {
TabView(selection: $selectedTab) {
TeamsListView()
.tag(Tab.teams)
TransactionDetailView()
.tag(Tab.transactions)
ScoreboardView()
.tag(Tab.gameplan)
LiveGameListView()
.tag(Tab.liveticker)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
askForAttachment.toggle()
} label: {
HStack {
Text("Email Support")
.font(.smallHeadline)
Image(systemName: "envelope.circle.fill")
.font(.bigHeadline)
}
.foregroundStyle(colorScheme == .light ? .black : .white)
}
}
}
.sheet(isPresented: $showEmail) {
MailView(supportEmail: $email) { result in
switch result {
case .success:
print("Email sent")
case .failure(let error):
print(error.localizedDescription)
}
}
}
.confirmationDialog("", isPresented: $askForAttachment) {
Button(LocalizedStringKey("Yes")) {
if email.data == nil {
email.send(openURL: openURL)
} else {
if MailView.canSendMail {
showEmail.toggle()
} else {
print("""
This device does not support email
\(email.body)
"""
)
}
}
}
Button(LocalizedStringKey("No")) {
email.send(openURL: openURL)
}
} message: {
Text(LocalizedStringKey("Do you use the Apple Mail App?"))
}
}
TabBarView3(selectedTab: selectedTab)
.padding(.bottom, 80)
.frame(height: 70)
}
}
.ignoresSafeArea()
}
}
}
#Preview {
MainTabView()
}
And here is the code from the custom bar with the animation stuff:
//
// TabBarView3.swift
// CustomTabBar
//
//
//
import SwiftUI
struct TabBarView3: View {
@State var selectedTab : Tab
var body: some View {
TabsLayoutView(selectedTab : selectedTab)
.padding()
.background(
Capsule()
.fill(.blue.opacity(0.2))
)
.frame(height: 70)
.shadow(radius: 30)
}
}
fileprivate struct TabsLayoutView: View {
@State var selectedTab: Tab
@Namespace var namespace
var body: some View {
HStack {
ForEach(Tab.allCases) { tab in
TabButton(tab: tab, selectedTab: $selectedTab, namespace: namespace)
}
}
}
private struct TabButton: View {
let tab: Tab
@Binding var selectedTab: Tab
var namespace: Namespace.ID
@State private var selectedOffset: CGFloat = 0
@State private var rotationAngle: CGFloat = 0
var body: some View {
Button {
withAnimation(.easeInOut) {
selectedTab = tab
}
selectedOffset = -60
if tab < selectedTab {
rotationAngle += 360
} else {
rotationAngle -= 360
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
selectedOffset = 0
if tab < selectedTab {
rotationAngle += 720
} else {
rotationAngle -= 720
}
}
} label: {
ZStack {
if isSelected {
Capsule()
.fill(tab.color.opacity(0.2))
.matchedGeometryEffect(id: "Selected Tab", in: namespace)
}
HStack(spacing: 10) {
Image(systemName: tab.icon)
.font(.system(size: 20, weight: .semibold, design: .rounded))
.foregroundColor(isSelected ? tab.color : .black.opacity(0.6))
.rotationEffect(.degrees(rotationAngle))
.scaleEffect(isSelected ? 1 : 0.9)
.animation(.easeInOut, value: rotationAngle)
.opacity(isSelected ? 1 : 0.7)
.padding(.leading, isSelected ? 20 : 0)
.padding(.horizontal, selectedTab != tab ? 10 : 0)
.offset(y: selectedOffset)
.animation(.default, value: selectedOffset)
if isSelected {
Text(tab.title)
.font(.system(size: 20, weight: .semibold, design: .rounded))
.foregroundColor(tab.color)
.padding(.trailing, 20)
}
}
.padding(.vertical, 10)
}
}
.buttonStyle(.plain)
}
private var isSelected: Bool {
selectedTab == tab
}
}
}
struct TabBarView3_Previews: PreviewProvider {
static var previews: some View {
TabBarView3(selectedTab: Tab.teams)
.frame(height: 70)
.padding(.horizontal)
}
}
Any help appreciated.
Cheers
David