Published on

SwiftUI'da shaxsiy (Custom) navigation bar yaratish

Authors

Nima uchun tayyor NavigationView yetarli emas?

SwiftUI dagi NavigationView juda zo'r va xotirada tez ishlaydi. Biroq, undagi .navigationBarTitle orqali faqat matnni o'zgartirish mumkin xolos. Orqa fon rangini o'zgartirish, ikkita qatorli title/subtitle yasash yoki sarlavhani o'rtaga joylashtirish doimiy muammo bo'lib kelgan.

Buning yechimi — tayyor NavigationView imkoniyatlaridan (navigatsiya tezligidan) foydalangan holda, faqat uning sarlavha qismini yashirib (.navigationBarHidden(true)), o'rniga o'zimizning Custom Bar'imizni chizishdir.

1. Custom nav bar view yasaymiz

Eng asosiysi tepadagi ko'k (yoki o'zimiz xohlagan) fonli, ortga qaytish tugmasi va markaziy yozuvlari bor View yaratish:

import SwiftUI

struct CustomNavBarView: View {
    @Environment(\.presentationMode) var presentationMode // Ortga qaytish uchun

    let title: String
    let subtitle: String?
    let showBackButton: Bool

    var body: some View {
        HStack {
            if showBackButton {
                backButton
            }

            Spacer()

            titleSection

            Spacer()

            if showBackButton {
                backButton.opacity(0) // O'rtada qolishi uchun ko'rinmas tugma
            }
        }
        .padding()
        .accentColor(.white)
        .foregroundColor(.white)
        .font(.headline)
        .background(Color.blue.ignoresSafeArea(edges: .top)) // Bizning xohlagan rang!
    }

    private var backButton: some View {
        Button(action: {
            presentationMode.wrappedValue.dismiss()
        }) {
            Image(systemName: "chevron.left")
        }
    }

    private var titleSection: some View {
        VStack(spacing: 4) {
            Text(title)
                .font(.title)
                .fontWeight(.semibold)

            if let subtitle = subtitle {
                Text(subtitle)
            }
        }
    }
}

2. Container (Quticha) yasaymiz

Biz yaratgan Nav Bar har doim ekranning eng tepasida turishi va uning tagidan bizning qolgan barcha ekranlarimiz chiqishi kerak. Generics (<Content: View>) va @ViewBuilder yordamida bu oson.

struct CustomNavBarContainerView<Content: View>: View {
    let content: Content

    // Aslida bu yerda PreferenceKey orqali keladigan title/subtitle lar @State qilib saqlanadi
    @State private var title: String = "Sarlavha"
    @State private var subtitle: String? = "Qo'shimcha"
    @State private var showBackButton: Bool = true

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        VStack(spacing: 0) {
            CustomNavBarView(title: title, subtitle: subtitle, showBackButton: showBackButton)

            content
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
        // Asl Navigatsiya panelini yashiramiz
        .navigationBarHidden(true)
    }
}

3. Asl NavigationView ni o'rash

Bu sehr ishlashi uchun butun boshli loyihamizdagi NavigationView o'rniga o'zimizning CustomNavView ni yozamiz.

struct CustomNavView<Content: View>: View {
    let content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        NavigationView {
            CustomNavBarContainerView {
                content
            }
            .navigationBarHidden(true)
        }
        .navigationViewStyle(.stack)
    }
}

Huddi shuningdek, NavigationLink larni ham o'zgartiramiz, chunki har bir yangi ochilgan oyna yana o'zining tepadagi CustomNavBarga ega bo'lishi kerak.

struct CustomNavLink<Label: View, Destination: View>: View {
    let destination: Destination
    let label: Label

    init(destination: Destination, @ViewBuilder label: () -> Label) {
        self.destination = destination
        self.label = label()
    }

    var body: some View {
        NavigationLink(
            destination: CustomNavBarContainerView {
                destination
            }
            .navigationBarHidden(true)
        ) {
            label
        }
    }
}

Qanday foydalaniladi?

Endi hamma tayyorgarliklar tugadi. Yangi ekranda bu juda oson va toza ishlaydi:

struct AppNavBarView: View {
    var body: some View {
        // Standard NavigationView o'rniga:
        CustomNavView {
            ZStack {
                Color.orange.ignoresSafeArea()

                // Standard NavigationLink o'rniga:
                CustomNavLink(destination: Text("Keyingi ekran!")) {
                    Text("Boshqa oynaga o'tish")
                        .foregroundColor(.white)
                }
            }
        }
    }
}

Tabriklaymiz! O'rganish juda qiyindek tuyulgan narsa aslida bizga cheksiz imkoniyat eshiklarini ochib beradi. O'rganilgan PreferenceKey usuli bilan aynan shu Custom Navigation Bar uchun ichki ekrandan sarlavha va qo'shimcha yozuvlarni jo'natish mexanizmini to'liq ishga tushirish mumkin bo'ladi.

Buy mea coffee