![スクリーンショット 2023-12-20 0 32 02](https://private-user-images.githubusercontent.com/52849416/291640629-e14378f4-67a1-4765-a9d3-9d998c530147.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE5Mzc5ODcsIm5iZiI6MTcyMTkzNzY4NywicGF0aCI6Ii81Mjg0OTQxNi8yOTE2NDA2MjktZTE0Mzc4ZjQtNjdhMS00NzY1LWE5ZDMtOWQ5OThjNTMwMTQ3LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzI1VDIwMDEyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWFlNjJhOTlkZDVjYWQyNThlOTRjZTU4OGJmOTM4MjZhYjRlZWZkMTNiNmY5MWE1ZWQ0NDI4MzRhNWI1YmI2MWYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.LxAzyXgrPRmCBTQC-K-3xQ2Bwg6TGhDUXfpqaoFwdNc)
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" | |
} | |
} | |
} |