• CustomTabBar 自定义选项卡视图


    1. 用到的技术点

      1) Generics      泛型

      2) ViewBuilder   视图构造器

      3) PreferenceKey 偏好设置

      4) MatchedGeometryEffect 几何效果

    2. 创建枚举选项卡项散列,TabBarItem.swift

    1. import Foundation
    2. import SwiftUI
    3. //struct TabBarItem: Hashable{
    4. // let iconName: String
    5. // let title: String
    6. // let color: Color
    7. //}
    8. ///枚举选项卡项散列
    9. enum TabBarItem: Hashable{
    10. case home, favorites, profile, messages
    11. var iconName: String{
    12. switch self {
    13. case .home: return "house"
    14. case .favorites: return "heart"
    15. case .profile: return "person"
    16. case .messages: return "message"
    17. }
    18. }
    19. var title: String{
    20. switch self {
    21. case .home: return "Home"
    22. case .favorites: return "Favorites"
    23. case .profile: return "Profile"
    24. case .messages: return "Messages"
    25. }
    26. }
    27. var color: Color{
    28. switch self {
    29. case .home: return Color.red
    30. case .favorites: return Color.blue
    31. case .profile: return Color.green
    32. case .messages: return Color.orange
    33. }
    34. }
    35. }

    3. 创建选项卡偏好设置 TabBarItemsPreferenceKey.swift

    1. import Foundation
    2. import SwiftUI
    3. /// 选项卡项偏好设置
    4. struct TabBarItemsPreferenceKey: PreferenceKey{
    5. static var defaultValue: [TabBarItem] = []
    6. static func reduce(value: inout [TabBarItem], nextValue: () -> [TabBarItem]) {
    7. value += nextValue()
    8. }
    9. }
    10. /// 选项卡项视图修饰符
    11. struct TabBarItemViewModifer: ViewModifier{
    12. let tab: TabBarItem
    13. @Binding var selection: TabBarItem
    14. func body(content: Content) -> some View {
    15. content
    16. .opacity(selection == tab ? 1.0 : 0.0)
    17. .preference(key: TabBarItemsPreferenceKey.self, value: [tab])
    18. }
    19. }
    20. extension View{
    21. /// 选项卡项视图修饰符
    22. func tabBarItem(tab: TabBarItem, selection: Binding<TabBarItem>) -> some View{
    23. modifier(TabBarItemViewModifer(tab: tab, selection: selection))
    24. }
    25. }

    4. 创建自定义选项卡视图 CustomTabBarView.swift

    1. import SwiftUI
    2. /// 自定义选项卡视图
    3. struct CustomTabBarView: View {
    4. let tabs: [TabBarItem]
    5. @Binding var selection: TabBarItem
    6. @Namespace private var namespace
    7. @State var localSelection: TabBarItem
    8. var body: some View {
    9. //tabBarVersion1
    10. tabBarVersion2
    11. .onChange(of: selection) { value in
    12. withAnimation(.easeInOut) {
    13. localSelection = value
    14. }
    15. }
    16. }
    17. }
    18. extension CustomTabBarView{
    19. /// 自定义 tabitem 布局
    20. private func tabView1(tab: TabBarItem) -> some View{
    21. VStack {
    22. Image(systemName: tab.iconName)
    23. .font(.subheadline)
    24. Text(tab.title)
    25. .font(.system(size: 12, weight: .semibold, design: .rounded))
    26. }
    27. .foregroundColor(localSelection == tab ? tab.color : Color.gray)
    28. .padding(.vertical, 8)
    29. .frame(maxWidth: .infinity)
    30. .background(localSelection == tab ? tab.color.opacity(0.2) : Color.clear)
    31. .cornerRadius(10)
    32. }
    33. /// 选项卡版本1
    34. private var tabBarVersion1: some View{
    35. HStack {
    36. ForEach(tabs, id: \.self) { tab in
    37. tabView1(tab: tab)
    38. .onTapGesture {
    39. switchToTab(tab: tab)
    40. }
    41. }
    42. }
    43. .padding(6)
    44. .background(Color.white.ignoresSafeArea(edges: .bottom))
    45. }
    46. /// 切换选项卡
    47. private func switchToTab(tab: TabBarItem){
    48. selection = tab
    49. }
    50. }
    51. extension CustomTabBarView{
    52. /// 自定义 tabitem 布局 2
    53. private func tabView2(tab: TabBarItem) -> some View{
    54. VStack {
    55. Image(systemName: tab.iconName)
    56. .font(.subheadline)
    57. Text(tab.title)
    58. .font(.system(size: 12, weight: .semibold, design: .rounded))
    59. }
    60. .foregroundColor(localSelection == tab ? tab.color : Color.gray)
    61. .padding(.vertical, 8)
    62. .frame(maxWidth: .infinity)
    63. .background(
    64. ZStack {
    65. if localSelection == tab{
    66. RoundedRectangle(cornerRadius: 10)
    67. .fill(tab.color.opacity(0.2))
    68. .matchedGeometryEffect(id: "background_rectangle", in: namespace)
    69. }
    70. }
    71. )
    72. }
    73. /// 选项卡版本 2
    74. private var tabBarVersion2: some View{
    75. HStack {
    76. ForEach(tabs, id: \.self) { tab in
    77. tabView2(tab: tab)
    78. .onTapGesture {
    79. switchToTab(tab: tab)
    80. }
    81. }
    82. }
    83. .padding(6)
    84. .background(Color.white.ignoresSafeArea(edges: .bottom))
    85. .cornerRadius(10)
    86. .shadow(color: Color.black.opacity(0.3), radius: 10, x: 0, y: 5)
    87. .padding(.horizontal)
    88. }
    89. }
    90. struct CustomTabBarView_Previews: PreviewProvider {
    91. static let tabs: [TabBarItem] = [.home, .favorites, .profile]
    92. static var previews: some View {
    93. VStack {
    94. Spacer()
    95. CustomTabBarView(tabs: tabs, selection: .constant(tabs.first!), localSelection: tabs.first!)
    96. }
    97. }
    98. }

    5. 创建自定义选项卡容器视图 CustomTabBarContainerView.swift

    1. import SwiftUI
    2. /// 自定义选项卡容器视图
    3. struct CustomTabBarContainerView<Content: View>: View {
    4. @Binding var selection: TabBarItem
    5. let content: Content
    6. @State private var tabs: [TabBarItem] = []
    7. init(selection: Binding<TabBarItem>, @ViewBuilder content: () -> Content){
    8. self._selection = selection
    9. self.content = content()
    10. }
    11. var body: some View {
    12. ZStack(alignment: .bottom) {
    13. content
    14. .ignoresSafeArea()
    15. CustomTabBarView(tabs: tabs, selection: $selection, localSelection: selection)
    16. }
    17. .onPreferenceChange(TabBarItemsPreferenceKey.self) { value in
    18. tabs = value
    19. }
    20. }
    21. }
    22. struct CustomTabBarContainerView_Previews: PreviewProvider {
    23. static let tabs: [TabBarItem] = [ .home, .favorites, .profile]
    24. static var previews: some View {
    25. CustomTabBarContainerView(selection: .constant(tabs.first!)) {
    26. Color.red
    27. }
    28. }
    29. }

    6. 创建应用选项卡视图 AppTabBarView.swift

    1. import SwiftUI
    2. // Generics 泛型
    3. // ViewBuilder 视图构造器
    4. // PreferenceKey 偏好设置
    5. // MatchedGeometryEffect 几何效果
    6. /// 应用选项卡视图
    7. struct AppTabBarView: View {
    8. @State private var selection: String = "Home"
    9. @State private var tabSelection: TabBarItem = .home
    10. var body: some View {
    11. /// 默认系统的 TabView
    12. // defaultTabView
    13. /// 自定义 TabView
    14. customTabView
    15. }
    16. }
    17. extension AppTabBarView{
    18. /// 默认系统的 TabView
    19. private var defaultTabView: some View{
    20. TabView(selection: $selection) {
    21. Color.red
    22. .ignoresSafeArea(edges: .top)
    23. .tabItem {
    24. Image(systemName: "house")
    25. Text("Home")
    26. }
    27. Color.blue
    28. .ignoresSafeArea(edges: .top)
    29. .tabItem {
    30. Image(systemName: "heart")
    31. Text("Favorites")
    32. }
    33. Color.orange
    34. .ignoresSafeArea(edges: .top)
    35. .tabItem {
    36. Image(systemName: "person")
    37. Text("Profile")
    38. }
    39. }
    40. }
    41. /// 自定义 TabView
    42. private var customTabView: some View{
    43. CustomTabBarContainerView(selection: $tabSelection) {
    44. Color.red
    45. .tabBarItem(tab: .home, selection: $tabSelection)
    46. Color.blue
    47. .tabBarItem(tab: .favorites, selection: $tabSelection)
    48. Color.green
    49. .tabBarItem(tab: .profile, selection: $tabSelection)
    50. Color.orange
    51. .tabBarItem(tab: .messages, selection: $tabSelection)
    52. }
    53. }
    54. }
    55. struct AppTabBarView_Previews: PreviewProvider {
    56. static var previews: some View {
    57. AppTabBarView()
    58. }
    59. }

    7. 效果图:

            

  • 相关阅读:
    【C语言】指针的进阶(三)—— 模拟实现qsort函数以及指针和数组的笔试题解析
    python之singledispatch单分派问题
    call\apply\bind详解
    SpringSecurity(三)- SpringSecurity 原理
    Android 开发入门教程-入门基础
    手把手教你Nginx常用模块详解之ngx_stream_ssl_module(七)
    哈莫尼斯 手工王国 Harmonis the hand made kingdoms,官方中文,解压即玩,
    阿里面试官:给我描述一下缓存击穿的现象,并说说你的解决思路?
    Linux--shell脚本详解
    15-基于Nginx构建Tomcat集群
  • 原文地址:https://blog.csdn.net/u011193452/article/details/133813459