1. 用到的技术点
1) Generics 泛型
2) ViewBuilder 视图构造器
3) PreferenceKey 偏好设置
4) MatchedGeometryEffect 几何效果
2. 创建枚举选项卡项散列,TabBarItem.swift
import Foundation
import SwiftUI//struct TabBarItem: Hashable{
// let iconName: String
// let title: String
// let color: Color
//}///枚举选项卡项散列
enum TabBarItem: Hashable{case home, favorites, profile, messagesvar iconName: String{switch self {case .home: return "house"case .favorites: return "heart"case .profile: return "person"case .messages: return "message"}}var title: String{switch self {case .home: return "Home"case .favorites: return "Favorites"case .profile: return "Profile"case .messages: return "Messages"}}var color: Color{switch self {case .home: return Color.redcase .favorites: return Color.bluecase .profile: return Color.greencase .messages: return Color.orange}}
}
3. 创建选项卡偏好设置 TabBarItemsPreferenceKey.swift
import Foundation
import SwiftUI/// 选项卡项偏好设置
struct TabBarItemsPreferenceKey: PreferenceKey{static var defaultValue: [TabBarItem] = []static func reduce(value: inout [TabBarItem], nextValue: () -> [TabBarItem]) {value += nextValue()}
}/// 选项卡项视图修饰符
struct TabBarItemViewModifer: ViewModifier{let tab: TabBarItem@Binding var selection: TabBarItemfunc body(content: Content) -> some View {content.opacity(selection == tab ? 1.0 : 0.0).preference(key: TabBarItemsPreferenceKey.self, value: [tab])}
}extension View{/// 选项卡项视图修饰符func tabBarItem(tab: TabBarItem, selection: Binding<TabBarItem>) -> some View{modifier(TabBarItemViewModifer(tab: tab, selection: selection))}
}
4. 创建自定义选项卡视图 CustomTabBarView.swift
import SwiftUI/// 自定义选项卡视图
struct CustomTabBarView: View {let tabs: [TabBarItem]@Binding var selection: TabBarItem@Namespace private var namespace@State var localSelection: TabBarItemvar body: some View {//tabBarVersion1tabBarVersion2.onChange(of: selection) { value inwithAnimation(.easeInOut) {localSelection = value}}}
}extension CustomTabBarView{/// 自定义 tabitem 布局private func tabView1(tab: TabBarItem) -> some View{VStack {Image(systemName: tab.iconName).font(.subheadline)Text(tab.title).font(.system(size: 12, weight: .semibold, design: .rounded))}.foregroundColor(localSelection == tab ? tab.color : Color.gray).padding(.vertical, 8).frame(maxWidth: .infinity).background(localSelection == tab ? tab.color.opacity(0.2) : Color.clear).cornerRadius(10)}/// 选项卡版本1private var tabBarVersion1: some View{HStack {ForEach(tabs, id: \.self) { tab intabView1(tab: tab).onTapGesture {switchToTab(tab: tab)}}}.padding(6).background(Color.white.ignoresSafeArea(edges: .bottom))}/// 切换选项卡private func switchToTab(tab: TabBarItem){selection = tab}
}extension CustomTabBarView{/// 自定义 tabitem 布局 2private func tabView2(tab: TabBarItem) -> some View{VStack {Image(systemName: tab.iconName).font(.subheadline)Text(tab.title).font(.system(size: 12, weight: .semibold, design: .rounded))}.foregroundColor(localSelection == tab ? tab.color : Color.gray).padding(.vertical, 8).frame(maxWidth: .infinity).background(ZStack {if localSelection == tab{RoundedRectangle(cornerRadius: 10).fill(tab.color.opacity(0.2)).matchedGeometryEffect(id: "background_rectangle", in: namespace)}})}/// 选项卡版本 2private var tabBarVersion2: some View{HStack {ForEach(tabs, id: \.self) { tab intabView2(tab: tab).onTapGesture {switchToTab(tab: tab)}}}.padding(6).background(Color.white.ignoresSafeArea(edges: .bottom)).cornerRadius(10).shadow(color: Color.black.opacity(0.3), radius: 10, x: 0, y: 5).padding(.horizontal)}
}struct CustomTabBarView_Previews: PreviewProvider {static let tabs: [TabBarItem] = [.home, .favorites, .profile]static var previews: some View {VStack {Spacer()CustomTabBarView(tabs: tabs, selection: .constant(tabs.first!), localSelection: tabs.first!)}}
}
5. 创建自定义选项卡容器视图 CustomTabBarContainerView.swift
import SwiftUI/// 自定义选项卡容器视图
struct CustomTabBarContainerView<Content: View>: View {@Binding var selection: TabBarItemlet content: Content@State private var tabs: [TabBarItem] = []init(selection: Binding<TabBarItem>, @ViewBuilder content: () -> Content){self._selection = selectionself.content = content()}var body: some View {ZStack(alignment: .bottom) {content.ignoresSafeArea()CustomTabBarView(tabs: tabs, selection: $selection, localSelection: selection)}.onPreferenceChange(TabBarItemsPreferenceKey.self) { value intabs = value}}
}struct CustomTabBarContainerView_Previews: PreviewProvider {static let tabs: [TabBarItem] = [ .home, .favorites, .profile]static var previews: some View {CustomTabBarContainerView(selection: .constant(tabs.first!)) {Color.red}}
}
6. 创建应用选项卡视图 AppTabBarView.swift
import SwiftUI// Generics 泛型
// ViewBuilder 视图构造器
// PreferenceKey 偏好设置
// MatchedGeometryEffect 几何效果/// 应用选项卡视图
struct AppTabBarView: View {@State private var selection: String = "Home"@State private var tabSelection: TabBarItem = .homevar body: some View {/// 默认系统的 TabView// defaultTabView/// 自定义 TabViewcustomTabView}
}extension AppTabBarView{/// 默认系统的 TabViewprivate var defaultTabView: some View{TabView(selection: $selection) {Color.red.ignoresSafeArea(edges: .top).tabItem {Image(systemName: "house")Text("Home")}Color.blue.ignoresSafeArea(edges: .top).tabItem {Image(systemName: "heart")Text("Favorites")}Color.orange.ignoresSafeArea(edges: .top).tabItem {Image(systemName: "person")Text("Profile")}}}/// 自定义 TabViewprivate var customTabView: some View{CustomTabBarContainerView(selection: $tabSelection) {Color.red.tabBarItem(tab: .home, selection: $tabSelection)Color.blue.tabBarItem(tab: .favorites, selection: $tabSelection)Color.green.tabBarItem(tab: .profile, selection: $tabSelection)Color.orange.tabBarItem(tab: .messages, selection: $tabSelection)}}
}struct AppTabBarView_Previews: PreviewProvider {static var previews: some View {AppTabBarView()}
}
7. 效果图: