Published on

SwiftUI'da to'liq shaxsiy (Custom) Tab Bar yaratish

Authors

Nega custom tab bar kerak?

SwiftUI dagi standart TabView ko'p hollarda yetarli. Lekin ba'zida dizaynerlar o'rtada kattalashib turuvchi, chetlari qiya (curved), bosganda ajoyib animatsiya beruvchi pastki menyularni (Tab Bar) xohlashadi. Standart TabView bunday erkinlikni bermaydi. Buni to'g'rilash uchun biz 3 bosqichli tizim yig'amiz:

  1. Pastki menyu dizayni (CustomTabBarView)
  2. Butun ekranni ushlab turuvchi quti (CustomTabBarContainerView)
  3. Ekranga Tab ma'lumotlarini uzatuvchi mexanizm (PreferenceKey)

Agar siz oldingi darslarda Generics, @ViewBuilder va PreferenceKey ni o'rganmagan bo'lsangiz, bu dars biroz qiyin bo'lishi mumkin!

1. Pastki menyu (CustomTabBarView)

Birinchi navbatda tab bar elementlarimiz qanday ko'rinishini model qilib olamiz:

import SwiftUI

// Hashable qilinishiga sabab: ForEach ichida ishlatamiz
struct TabBarItem: Hashable {
    let iconName: String
    let title: String
    let color: Color
}

Endi uning ko'rinishini chizamiz.

struct CustomTabBarView: View {
    let tabs: [TabBarItem]
    @Binding var selection: TabBarItem // Qaysi biri tanlangani

    var body: some View {
        HStack {
            ForEach(tabs, id: \.self) { tab in
                tabView(tab: tab)
                    .onTapGesture {
                        switchToTab(tab: tab)
                    }
            }
        }
        .padding(6)
        .background(Color.white.ignoresSafeArea(edges: .bottom))
    }

    // Bitta Tab qanday ko'rinadi?
    private func tabView(tab: TabBarItem) -> some View {
        VStack {
            Image(systemName: tab.iconName)
            Text(tab.title)
        }
        .foregroundColor(selection == tab ? tab.color : .gray)
        .padding(.vertical, 8)
        .frame(maxWidth: .infinity)
        .background(selection == tab ? tab.color.opacity(0.2) : .clear)
        .cornerRadius(10)
    }

    private func switchToTab(tab: TabBarItem) {
        withAnimation(.easeInOut) {
            selection = tab
        }
    }
}

2. Elementlarni yig'uvchi PreferenceKey

Asl TabView qanday ishlashini eslasangiz: biz .tabItem { } orqali ichki (child) view dan turib menyuga element qo'shamiz. Buni Custom qilish uchun PreferenceKey kerak!

struct TabBarItemsPreferenceKey: PreferenceKey {
    static var defaultValue: [TabBarItem] = []

    static func reduce(value: inout [TabBarItem], nextValue: () -> [TabBarItem]) {
        value += nextValue() // Yangi qo'shilgan tabni array ga qo'shamiz
    }
}

// Buni ishlatish uchun ViewModifier yasaymiz
struct TabBarItemViewModifier: ViewModifier {
    let tab: TabBarItem
    @Binding var selection: TabBarItem

    func body(content: Content) -> some View {
        content
            .opacity(selection == tab ? 1.0 : 0.0) // Tanlanmagan bo'lsa yashiramiz
            .preference(key: TabBarItemsPreferenceKey.self, value: [tab])
    }
}

extension View {
    func customTabBarItem(tab: TabBarItem, selection: Binding<TabBarItem>) -> some View {
        self.modifier(TabBarItemViewModifier(tab: tab, selection: selection))
    }
}

3. Container View (Quticha) yasash

Endi tepadagi va pastki qismlarni birlashtiramiz. Bu Container ekranlarni ZStack ichida ushlab turadi va ularning preference key larini yig'adi.

struct CustomTabBarContainerView<Content: View>: View {
    @Binding var selection: TabBarItem
    let content: Content

    @State private var tabs: [TabBarItem] = []

    init(selection: Binding<TabBarItem>, @ViewBuilder content: () -> Content) {
        self._selection = selection
        self.content = content()
    }

    var body: some View {
        VStack(spacing: 0) {
            ZStack {
                content
            }

            CustomTabBarView(tabs: tabs, selection: $selection)
        }
        .onPreferenceChange(TabBarItemsPreferenceKey.self) { value in
            self.tabs = value
        }
    }
}

4. Yakuniy ishlatish

Biz Apple'ning tayyor tabViewiga 99% o'xshaydigan, lekin o'zimiz xohlagandek boshqarish mumkin bo'lgan menyu yasadik:

struct AppTabBarView: View {
    @State private var selection: TabBarItem = TabBarItem(iconName: "house", title: "Home", color: .blue)

    var body: some View {
        CustomTabBarContainerView(selection: $selection) {

            Color.blue
                .customTabBarItem(tab: TabBarItem(iconName: "house", title: "Home", color: .blue), selection: $selection)

            Color.red
                .customTabBarItem(tab: TabBarItem(iconName: "heart", title: "Favorites", color: .red), selection: $selection)

            Color.green
                .customTabBarItem(tab: TabBarItem(iconName: "person", title: "Profile", color: .green), selection: $selection)
        }
    }
}

Endi siz CustomTabBarView kodiga xohlagan dizayningizni, animatsiyalarni qiyinchiliksiz qo'sha olasiz. Ekranda har bir oyna ajoyib animatsiya bilan almashadi!

Buy mea coffee