https://medium.com/geekculture/custom-tabbar-in-swiftui-4d239410ee73
| import SwiftUI | |
| struct HomeView: View { | |
| var body: some View { | |
| Text("HomeView") | |
| } | |
| } | |
| struct FavoriteView: View { | |
| var body: some View { | |
| Text("FavoriteView") | |
| } | |
| } | |
| struct NewsView: View { | |
| var body: some View { | |
| Text("NewsView") | |
| } | |
| } | |
| struct ProfileView: View { | |
| var body: some View { | |
| Text("ProfileView") | |
| } | |
| } | |
| struct ContentView: View { | |
| @State var selectedIndex = 0 | |
| var body: some View { | |
| ZStack(alignment: .bottom) { | |
| TabView(selection: $selectedIndex) { | |
| HomeView() | |
| .tag(TabbarItem.home.rawValue) | |
| FavoriteView() | |
| .tag(TabbarItem.favorite.rawValue) | |
| NewsView() | |
| .tag(TabbarItem.news.rawValue) | |
| ProfileView() | |
| .tag(TabbarItem.profile.rawValue) | |
| } | |
| .frame(width: CGFloat((80 * (TabbarItem.allCases.count - 1)) + 120)) | |
| .padding(.vertical, 26) | |
| ZStack { | |
| HStack { | |
| ForEach(TabbarItem.allCases, id: \.self) { item in | |
| Button { | |
| selectedIndex = item.rawValue | |
| } label: { | |
| tabItemView(tabbarItem: item, isActive: selectedIndex == item.rawValue) | |
| } | |
| } | |
| } | |
| .padding(6) | |
| } | |
| .frame(height: 70) | |
| .background(.blue.opacity(0.2)) | |
| .cornerRadius(15) | |
| .padding(.vertical, 26) | |
| } | |
| } | |
| } | |
| extension ContentView { | |
| func tabItemView(tabbarItem: TabbarItem, isActive: Bool) -> some View { | |
| HStack { | |
| Spacer() | |
| Image(systemName: tabbarItem.iconName) | |
| .resizable() | |
| .renderingMode(.template) | |
| .foregroundColor(isActive ? .black : .gray) | |
| .frame(width: 20, height: 20) | |
| if let title = tabbarItem.title, isActive { | |
| Text(title) | |
| .lineLimit(1) | |
| .font(.system(size: 14)) | |
| .foregroundColor(isActive ? .black : .gray) | |
| } | |
| Spacer() | |
| } | |
| .frame(width: isActive ? 120 : 80, height: 60) | |
| .background(isActive ? .blue.opacity(0.4) : .clear) | |
| .cornerRadius(10) | |
| } | |
| } | |
| enum TabbarItem: Int, CaseIterable { | |
| case home | |
| case favorite | |
| case news | |
| case profile | |
| var title: String? { | |
| switch self { | |
| case .home: | |
| return "Home" | |
| case .favorite: | |
| return "Favorite" | |
| case .news: | |
| return "News" | |
| case .profile: | |
| return nil | |
| } | |
| } | |
| var iconName: String { | |
| switch self { | |
| case .home: | |
| return "house" | |
| case .favorite: | |
| return "heart" | |
| case .news: | |
| return "newspaper" | |
| case .profile: | |
| return "person.crop.circle" | |
| } | |
| } | |
| } |