- Published on
SwiftUI'da @ViewBuilder bilan ishlash
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
@ViewBuilder o'zi nima?
SwiftUI da VStack yoki HStack larni ko'p ishlatamiz. E'tibor berganmisiz, ularning figurali qavslari ichiga { } istalgancha va istalgan turdagi View larni yozishingiz mumkin. Bu aynan @ViewBuilder degan atribut sharofati bilan ishlaydi. U bitta kod bloki (closure) ichida bir nechta View larni yig'ib, orqa fonda ularni bitta yagona View ga aylantirib beradi.
Oddiy muammo
Deylik, bizda ekranning sarlavhasi (Header) uchun tayyor dizayn bor. Lekin uning sarlavha tagiga chiqadigan narsalari har xil: bitta ekranda oddiy yozuv chiqishi kerak, ikkinchisida esa yurakcha rasmi, uchinchisida umuman hech narsa chiqmasligi kerak.
Buni oddiy yo'l bilan qilsak, barcha ehtimoliy o'zgaruvchilarni init qilishga to'g'ri kelardi:
struct HeaderViewRegular: View {
let title: String
let description: String?
let iconName: String?
// ...
}
Buning o'rniga, keling o'zimizning qutichamizni (Xuddi HStack kabi) yasaymiz!
1. Custom quti yasash (Generic + ViewBuilder)
Oldingi darsda o'rganganimizdek, View qabul qiluvchi <Content: View> turini yozamiz. Eng muhim joyi: uning initsializatori oldiga @ViewBuilder qo'shamiz!
import SwiftUI
// Content faqat View bo'la oladi
struct HeaderViewGeneric<Content: View>: View {
let title: String
let content: Content // Bu bizning ichkariga yoziladigan View'lar
// Initsializatorda @ViewBuilder ishlatamiz!
init(title: String, @ViewBuilder content: () -> Content) {
self.title = title
self.content = content()
}
var body: some View {
VStack(alignment: .leading) {
Text(title)
.font(.largeTitle)
.fontWeight(.bold)
// Biz uzatgan barcha narsalar shu yerda chiqadi
content
RoundedRectangle(cornerRadius: 5)
.frame(height: 2)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
}
}
Ana endi bu komponentni ishlatsak, xuddi VStack kabi ochib-yopiladigan qavslarga ega bo'lamiz:
struct ViewBuilderBootcamp: View {
var body: some View {
VStack {
// 1-xil ishlatilish: Faqat rasm
HeaderViewGeneric(title: "Rasm bilan") {
Image(systemName: "heart.fill")
.foregroundColor(.red)
}
// 2-xil ishlatilish: Matn va Rasm birga (HStack ichida)
HeaderViewGeneric(title: "Aralash ko'rinish") {
HStack {
Text("Bu murakkab")
Image(systemName: "bolt.fill")
.foregroundColor(.yellow)
}
}
}
}
}
Bu sizning kodingizni qanchalik toza va moslashuvchan qilishini tasavvur qilyapsizmi?!
2. @ViewBuilder ni O'zgaruvchilar (Variables) bilan ishlatish
Agar sizda bitta o'zgaruvchi shartlarga qarab xar xil View larni qaytarishi kerak bo'lsa (Masalan bitta if ichida Text, else ichida Image qaytsa) Xcode xato beradi: "Opaque return type mismatch". Uni tuzatish uchun o'zgaruvchining tepasiga ham shunchaki @ViewBuilder deb yozib qo'yishimiz kifoya!
struct LocalViewBuilderBootcamp: View {
var type: Int
var body: some View {
VStack {
headerSection
}
}
// @ViewBuilder funksiyaga har xil turdagi View'larni xatosiz qaytarish imkonini beradi
@ViewBuilder private var headerSection: some View {
if type == 1 {
Text("Birinchi turdagi sarlavha")
} else if type == 2 {
Image(systemName: "heart.fill")
.foregroundColor(.red)
} else {
VStack {
Text("Uchinchi tur")
Image(systemName: "star.fill")
}
}
}
}
Xulosa
@ViewBuilderbir nechta View'larni yig'ib bitta yaxlit View ga aylantiradi.- Uni Generics (
<Content: View>) bilan birgalikda ishlatib, moslashuvchan va professional komponentlar yaratish mumkin. - Uni O'zgaruvchilar oldidan yozish orqali, kod ichida if/else bilan har xil turdagi View larni xatosiz qaytarish mumkin.