- Published on
SwiftUI-da TabView va PageTabViewStyle bilan tab bar yaratish
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
SwiftUI Bootcamp-ga xush kelibsiz qaytib! Men — Nick, va ushbu juda muhim videoda biz TabView komponentini ko'rib chiqamiz. Nomidan ham ko'rinib turganidek, bu — ilovangizning pastki qismida o'sha tablarni hosil qilishning eng oson, standart usuli.
Tashqaridagi ko'plab ilovalarni ochsangiz, ularning pastida bosib o'tishingiz mumkin bo'lgan to'rt-besh ta tab borligini ko'rasiz — siz tab-ni bosganingizda, sahifa o'zgaradi. Aynan shuni biz hozir amalga oshiramiz, va SwiftUI-dagi TabView komponenti orqali buni qilish juda oson.
Avval, qanday qilib oddiy, asosiy TabView qo'sha olishimizni ko'rib chiqamiz, so'ngra uni maxsus ikonkalar va ranglar bilan moslashtirishni ko'ramiz. Keyin biz buni bir qadam ilgariga olib borib, tab-larni dasturiy ravishda (programmatically) qanday o'zgartirish mumkinligini ko'ramiz — ya'ni faqat pastdagi tab-larni bosish o'rniga, buni kod orqali qanday amalga oshirish mumkinligini, o'zimizning maxsus tugmalarimiz va funksiyalarimizni yaratishni ko'ramiz. Va nihoyat, biz oddiy TabView-ni page tab viewga aylantiramiz — bu SwiftUI-ning juda qiziqarli va qulay modifikatori, u orqali TabView-ni pagerga aylantirib, barcha tab-lar orasida suriб (swipe) o'ta olamiz. Bu yerda ham, buni qanday moslashtirib, mukammal ko'rinishga keltirish mumkinligini ko'rsataman.
Yangi SwiftUI fayl yaratish
Xcode loyihamizga qaytamiz. Navigator-da o'ng tugmani bosib, yangi fayl yaratamiz — bu SwiftUI View bo'ladi, va unga TabViewBootcamp deb nom beramiz. Create tugmasini bosamiz, ichiga kirgandan so'ng, canvas-da Resume tugmasini bosamiz, va kod yozishni boshlaymiz.
Oddiy TabView yaratish
Oddiy TabView, aynan o'ylagandek — ilovangiz pastiga tab-lar qo'shadi. TabView deb yozib, qavslarni ochamiz — bu yerda ikki xil tugatish (completion) variant mavjud: biri selection bilan, biri esa shunchaki content. Hozircha faqat content bilan boshlaymiz.
TabView ichida bizga bir nechta tab kerak. Avval birinchi tabni qo'shamiz — matn (text) qo'shib, unga "Home Tab" deb yozamiz:
TabView {
Text("Home Tab")
}
Birinchi matnni qo'shganimizda, oldindan ko'rishni kattalashtirib qarasak — pastda allaqachon tab bar paydo bo'lganini ko'ramiz, ammo hech qanday tab ko'rinmaydi, chunki bizda hali tabItem yo'q.
Shuning uchun shu matnga .tabItem qo'shamiz. tabItemga label kerak bo'ladi — labelni yozib, qavslarni ochsak, Xcode-da label ko'rganingizda, bu, mohiyatan, string turidagi sarlavha (title) va bir rasm (image)ni so'rayotganini ko'rasiz. Bu tugatish variantidan foydalanishimiz mumkin edi, ammo men buni unchalik yoqtirmayman — buning ancha tozaroq yo'li bor.
Shuning uchun, shunchaki Enter tugmasini bosib, tabItem ichiga qo'lda matn va rasm qo'shamiz. Avval rasmdan boshlaymiz — systemName orqali, "house.fill"ni ishlatamiz:
TabView {
Text("Home Tab")
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
}
Bizning home tabimiz pastda allaqachon paydo bo'ldi.
Yana ikkita tab qo'shish
Keling, yana bir nechta tab qo'shamiz. Shu matndan pastga yana bittasini qo'shamiz — "Browse Tab", va yana tabItem qo'shamiz:
Text("Browse Tab")
.tabItem {
Image(systemName: "globe")
Text("Browse")
}
Yana bittasini ham qo'shamiz:
Text("Profile Tab")
.tabItem {
Image(systemName: "person.fill")
Text("Profile")
}
Endi siz allaqachon tab-larimiz pastda qanday ishlayotganini ko'rib turibsiz. Canvas-da Resume tugmasini bosib, shu tab-larni bosib ko'rsak, ular ekranni avtomatik ravishda yangilab turadi: profile tabda bo'lganimizda, kontent — "Profile Tab"; home tabga o'tganimizda — "Home Tab".
Tab-larning rangini o'zgartirish
Tab-lar, albatta, bizning accent colorimizga ega bo'ladi — bu standart holatda ko'k. TabView-ning pastiga .accentColor qo'shib, masalan .red deb belgilab, shu tab-larning rangini o'zgartirishimiz mumkin:
TabView {
// ...
}
.accentColor(.red)
Home tab uchun haqiqiy view yaratish
Keling, buni biroz yaxshiroq ko'rinishga keltiramiz. Endi home tab uchun shunchaki matn o'rniga, haqiqiy view yasaymiz. ZStack yaratamiz, fon qatlam sifatida qizil rang qo'yamiz, va uning ustiga "Home Tab" matnini joylashtiramiz:
ZStack {
Color.red
.ignoresSafeArea()
Text("Home Tab")
.font(.largeTitle)
.foregroundColor(.white)
}
Bu yaxshi ko'rinmoqda — endi home tabimiz uchun barcha kodimiz shu yerda joylashganini ko'rib turasiz.
Sub-view sifatida ajratib olish
Command tugmasini bosib turib, shu ZStack ustiga bosamiz, va "Extract Sub View" variantini tanlaymiz — bu amalni oldingi videolarda allaqachon qilgan edik. Shu tanlangan holatda, nomini HomeView deb o'zgartiramiz.
Ko'rinib turibdi, tabItem ham birga ko'chib ketgan — uni qaytarib olamiz. Endi bizning HomeViewimiz pastda, o'zining alohida structi sifatida turibdi. tabItemni qirqib olamiz (u bilan birga ketmasligi kerak edi), va uni TabViewda qoldiramiz:
TabView {
HomeView()
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
Text("Browse Tab")
.tabItem {
Image(systemName: "globe")
Text("Browse")
}
Text("Profile Tab")
.tabItem {
Image(systemName: "person.fill")
Text("Profile")
}
}
.accentColor(.red)
struct HomeView: View {
var body: some View {
ZStack {
Color.red
.ignoresSafeArea()
Text("Home Tab")
.font(.largeTitle)
.foregroundColor(.white)
}
}
}
Endi siz haqiqiy ilovada, masalan, bosh sahifa (home page) uchun haqiqiy kodingiz qanday qilib o'zining alohida structida bo'lishi mumkinligini ko'rib turasiz. Hozir bizda HomeView shu yerda, ammo bu boshqa faylda, ilovamizning istalgan joyida bo'lishi mumkin edi. Va home view uchun butun mantiqimiz aynan shu yerda bo'ladi. Shunday qilib, TabView-ni yaratganimizda, bizga shunchaki HomeView va tabItem qo'shish kifoya — tab bar-imizni ishga tushirish shunchalik oddiy.
Tanlovni (selection) boshqarish
TabViewni init qilganimizda — TabView( deb yozib qavsni ochganimizda — yana bir tugatish variant bor edi, bu selection bilan, va u binding qiymatga ega edi. Demak, selection ham parametr sifatida berilishi mumkin.
Shuning uchun, TabView-imizga selectionni qo'shamiz. Bu — biror qiymatga bog'langan (binding) bo'lishi kerak, shuning uchun yuqorida selectedTab nomli o'zgaruvchi yaratamiz:
@State var selectedTab: Int = 2
Endi selection uchun $selectedTabni beramiz:
TabView(selection: $selectedTab) {
// ...
}
Har bir tab uchun tag qo'shish
Endi TabView-ga, bu tab-larning qaysi biri nol, bir yoki ikkinchi raqam ekanligini bildirish uchun, har biriga tag qo'shishimiz kerak. Shuning uchun, tabItemdan keyin .tag qo'shamiz: birinchisiga — tag(0), ikkinchisiga — tag(1), uchinchisiga — tag(2):
TabView(selection: $selectedTab) {
HomeView()
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
.tag(0)
Text("Browse Tab")
.tabItem {
Image(systemName: "globe")
Text("Browse")
}
.tag(1)
Text("Profile Tab")
.tabItem {
Image(systemName: "person.fill")
Text("Profile")
}
.tag(2)
}
.accentColor(.red)
selectedTab qiymati 2ga teng bo'lgani uchun, biz profile tabida boshlanishimiz kerak. Resume tugmasini bosib ko'rsak — haqiqatan ham, ilova ishga tushganda, biz profile tabida turibmiz.
Tab-ni dasturiy ravishda o'zgartirish
Endi, foydalanuvchiga faqat tab-larni bosish orqali tab-larni almashtirish imkonini berish o'rniga, biz buni dasturiy ravishda ham, shunchaki selectedTabni o'zgartirish orqali amalga oshira olamiz.
HomeView ichiga, bosilganda profile tabga o'tib ketadigan bir tugma qo'shamiz. HomeView ustiga o'ng tugmani bosib, "Jump to Definition" orqali HomeView qayerda joylashganiga o'tamiz.
Avval, oldindan ko'rishda HomeViewning qanday ko'rinishini ko'rish uchun, selectedTabni vaqtincha 0ga qaytaramiz.
Endi HomeView ichida, home tab matni ostiga, tugma qo'shamiz — action va label bilan, actionni hozircha bo'sh qoldiramiz, va tugma matni — "Go to Profile":
Ko'rinib turibdi, biz ZStack ichidamiz, shuning uchun matn va tugmani VStack ichiga olamiz:
struct HomeView: View {
@State var selectedTab: Int = 0
var body: some View {
ZStack {
Color.red
.ignoresSafeArea()
VStack {
Text("Home Tab")
.font(.largeTitle)
.foregroundColor(.white)
Button {
// hozircha bo'sh
} label: {
Text("Go to Profile")
.font(.headline)
.padding()
.padding(.horizontal)
.background(Color.white)
.cornerRadius(10)
}
}
}
}
}
Tugma matni standart holatda qizil rangda ko'rinadi, chunki tab bar-imizda biz red accent color o'rnatgan edik. Shuning uchun, uni ko'rish uchun, .background(Color.white) qo'shamiz — endi uni ko'ra olamiz. Fon (background)dan oldin, padding qo'shamiz, va biroz qo'shimcha gorizontal padding ham qo'shamiz, so'ngra burchak radiusini 10 qilamiz — endi bizda chiroyli "Go to Profile" tugmasi bor.
Tugma orqali selectedTabni o'zgartirish
Endi shu tugmani bosganimizda, biz profile tabga o'tishni xohlaymiz. Buning uchun tugma ichida selectionni, ya'ni selectedTabni o'zgartirishimiz kerak. Esingizda bo'lsa, selectedTab — bu shu (asosiy) view-da e'lon qilingan state o'zgaruvchisi. Biz buni o'zimizning ikkinchi darajali viewimizda (HomeViewda) o'zgartirishni xohlayotganimiz uchun, bizga binding kerak bo'ladi — men buni oldingi videoda allaqachon ko'rib chiqgan edim, shuning uchun bu sizga tanish bo'lishi kerak.
Shuning uchun, HomeViewda @Binding var selectedTab: Int qo'shamiz, va tugmani bosganimizda, selectedTab = 2 qilamiz — shunday qilib, biz profile tabga o'tib ketamiz:
struct HomeView: View {
@Binding var selectedTab: Int
var body: some View {
ZStack {
Color.red
.ignoresSafeArea()
VStack {
Text("Home Tab")
.font(.largeTitle)
.foregroundColor(.white)
Button {
selectedTab = 2
} label: {
Text("Go to Profile")
.font(.headline)
.padding()
.padding(.horizontal)
.background(Color.white)
.cornerRadius(10)
}
}
}
}
}
Endi HomeViewni init qilganimizda, bizga selectedTab uchun bir o'zgaruvchini bog'lash kerak bo'ladi — yuqorida shu haqida xatolik xabarini ko'rmoqdamiz. Buni tuzatamiz: bizga selectedTabni bog'lashimiz kerak, shuning uchun HomeView($selectedTab) deb yozamiz:
TabView(selection: $selectedTab) {
HomeView(selectedTab: $selectedTab)
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
.tag(0)
// ...
}
Shunchaki shu — endi Resume tugmasini bosib, oldindan ko'rishni ishga tushirsak: biz home tabidamiz, tab-larni bosib bir-biriga almashtirishimiz mumkin, yoki agar home tabda bo'lib, "Go to Profile" tugmasini bossak — biz darrov profile tabga o'tib ketamiz.
Endi sizlar tab bar-ni qanday sozlashni, va tanlovni dasturiy ravishda qanday yangilashni bilasiz.
Page Tab View — karusel (pager)
Videoni yakunlashdan oldin, sizlarga paging tab viewni ko'rsatmoqchiman — bu, asosan, karusel (carousel) kabi ishlaydi. Oddiy TabView, pastda shu tab-larni xohlasangiz, juda mos keladi, ammo endi biz boshqa bir formatga o'tamiz.
Bu keyingi view ancha boshqacha bo'lgani uchun, va bizga bu tab-itemlarning hech biri kerak bo'lmagani uchun, men butun shu TabView-ni belgilab, Command + / tugma birikmasi orqali, hammasini izohga olib qo'yaman.
Yangi TabView yaratish
Endi butunlay yangi TabView yaratamiz:
TabView {
RoundedRectangle(cornerRadius: 25)
RoundedRectangle(cornerRadius: 25)
RoundedRectangle(cornerRadius: 25)
}
Burchak radiusi 25 bo'lgan yumaloq to'rtburchak (RoundedRectangle) qo'shamiz, va uni nusxalab, ikki marta yana joylashtiramiz.
.tabViewStyle qo'shish
Endi .tabViewStyle qo'shamiz. Standart tabViewStyle — bizning yuqorida pastki tab bar bilan qilgan ishimiz edi. Buning o'rniga, tabViewStyle deb yoza boshlaymiz, va .page tab view style-ni tanlaymiz:
TabView {
RoundedRectangle(cornerRadius: 25)
RoundedRectangle(cornerRadius: 25)
RoundedRectangle(cornerRadius: 25)
}
.tabViewStyle(.page)
Natijani ko'raylik: pastdagi tab bar yo'qolib, endi bizda kichik uchta doiracha va paging tab view mavjud — bu, aslida, suriladigan (scrollable) paging view. Chapga va o'ngga suриб o'tishimiz mumkin.
Birinchisining rangini o'zgartiramiz — .foregroundColor(.red), va uchinchisini — .foregroundColor(.green), toki nima bo'layotganini yaxshiroq ko'rishimiz mumkin bo'lsin:
TabView {
RoundedRectangle(cornerRadius: 25)
.foregroundColor(.red)
RoundedRectangle(cornerRadius: 25)
RoundedRectangle(cornerRadius: 25)
.foregroundColor(.green)
}
.tabViewStyle(.page)
Bizda to'rtburchaklarimiz bor, va ularni haqiqatan ham varaqlab o'tishimiz mumkin. Buni kodimizga qo'shish juda oson edi, va bizda haqiqatan ham chiroyli, suriladigan karusel bor.
Frame bilan moslashtirish
Bu yerdan buni yanada moslashtirishimiz mumkin. Masalan, butun ekranni egallashi o'rniga, biz buni ma'lum bir balandlikka ega qilishni xohlaymiz. Shuning uchun, .frame qo'shib, balandligini, masalan, 300ga belgilaymiz:
TabView {
RoundedRectangle(cornerRadius: 25)
.foregroundColor(.red)
RoundedRectangle(cornerRadius: 25)
RoundedRectangle(cornerRadius: 25)
.foregroundColor(.green)
}
.tabViewStyle(.page)
.frame(height: 300)
Bu endi, ehtimol, TikTok-ning browse sahifasi yuqori qismida yoki kichikroq sahifalarda ko'rgan, turli reklamalar yoki turli rasmlarni ko'rsatuvchi shu paging karuselga ancha o'xshab qoldi. Bu shunchaki oddiy to'rtburchak emas, ammo bu sizga ko'plab ilovalarda ko'rgan narsaga juda tanish bo'lishi kerak.
Karuselga rasmlar qo'shish
Keling, buni bir necha qadam ilgariga olib boramiz, va bunga bir nechta rasm (icon) qo'shamiz. Yuqorida bir massiv (array) yaratamiz — icons nomli, stringlardan iborat massiv, va unga bir nechta sistema ikonkalari nomini joylashtiramiz:
let icons: [String] = ["heart.fill", "globe", "house.fill", "person.fill"]
Bularning barchasi sistema ikonkalari, shuning uchun ular ishlashi kerak.
ForEach bilan rasmlarni chiqarish
Endi TabView-dagi yumaloq to'rtburchaklarimizni olib tashlaymiz, va ForEach qo'shamiz — id va content tugatish variantidan foydalanamiz (ForEach haqida butun bir video qilgan edik, shuning uchun ular qanday ishlashini bilishingiz kerak):
TabView {
ForEach(icons, id: \.self) { icon in
Image(systemName: icon)
}
}
.tabViewStyle(.page)
.frame(height: 300)
Demak, biz icons massividagi har bir icon bo'ylab aylanamiz (loop), har biriga id beramiz — buning uchun shunchaki \.self yozamiz, bu unga avtomatik id beradi — va content qismida, har bir icon uchun, Image(systemName: icon) qo'shamiz, ya'ni shu ikonka nomini ishlatamiz.
Canvas-da Resume tugmasini bosib, natijani ko'raylik: bizda yurak (heart) ikonkasi bor, va chap-o'ngga suриб o'tishimiz mumkin bo'lishi kerak.
Rasmlarni moslashtirish
Rasmlarni .resizable() qilamiz, va .scaledToFit() qilamiz, toki ular biroz yaxshiroq ko'rinsin:
ForEach(icons, id: \.self) { icon in
Image(systemName: icon)
.resizable()
.scaledToFit()
}
Endi butun TabView-ga fon (background) beramiz — Color.red, toki to'g'ri sohada ekanligimizga ishonch hosil qilaylik:
TabView {
ForEach(icons, id: \.self) { icon in
Image(systemName: icon)
.resizable()
.scaledToFit()
}
}
.tabViewStyle(.page)
.frame(height: 300)
.background(Color.red)
Bu juda qiziq ko'rinmoqda — buni gradient bilan yanada yaxshiroq qilishimiz mumkin.
Radial gradient qo'shish
Avval RadialGradient qo'shamiz — ranglar uchun red va blueni ishlataylik (ko'k yaxshi ko'rinadi), center, startRadius va radius parametrlarini belgilaymiz. radiusni 300 qilamiz, chunki bizning frame-imiz allaqachon 300:
.background(
RadialGradient(
colors: [.red, .blue],
center: .center,
startRadius: 5,
endRadius: 300
)
)
Bu juda qiziq ko'rinmoqda. Endi rasmni biroz kichikroq qilamiz — atrofiga padding qo'shib, uni biroz ichkariga suramiz, padding miqdorini, masalan, 30 qilamiz:
ForEach(icons, id: \.self) { icon in
Image(systemName: icon)
.resizable()
.scaledToFit()
.padding(30)
}
Endi bizda juda qiziqarli TabView bor. Tasavvur qiling, agar bu ikonkalar haqiqatan ham rasmlar yoki shunga o'xshash narsa bo'lsa edi, va biz bu rasmlar orqali haqiqatan suриб o'ta olamiz — bu juda ajoyib ko'rinadi.
Albatta, haqiqiy ilovada siz bu yerda shunchaki ikonkalardan foydalanmasdingiz — buni yanada yaxshiroq ko'rinishga keltirar edingiz, ammo endi siz bu aniq qanday ishlashini bilasiz.
Eslatma: selection va tag
Yana bir bor: biz bu TabView-ga ham selection qo'shishimiz mumkin edi — agar dasturiy ravishda, masalan, to'rtinchi raqamga sakrab o'tishni xohlasak, buni qilishimiz mumkin edi. Va yana bir bor: agar bu TabView-ga selection qo'shsangiz, har bir itemga tag qo'shganingizga ishonch hosil qiling.
Esingizda bo'lsin, biz birinchi TabView-imizga selection qo'shganimizda, bizga tag ham qo'shishimiz kerak bo'lgan edi. Men ko'p odamlar shu joyda chalkashib qolganini ko'rganman — ular selection qo'shadi, ammo keyin tab pastidagi shu doirachalar aslida o'zgarmaydi, va buning sababi — siz TabView-ga, har bir item qaysi selectionga tegishli ekanligini bildiruvchi **tag**ni qo'shmagansiz.
Shuning uchun, agar selectiondan foydalansangiz, **tag**ni ham albatta qo'shing — aks holda, agar foydalanmasangiz, bu shunchaki o'z holicha ishlashi kerak, va bu yerda ko'rib turganimizdek, indekslar mukammal ishlamoqda.
Xulosa
Mana shu — bu video uchun shu qadar. Umid qilaman, sizlar biror narsa o'rgandingiz — TabView doim ishlatiladi, nafaqat paging uchun, balki shunchaki pastga tab-lar qo'yish uchun ham.
Albatta, mahoratingiz oshib, ilgariga ketganingiz sayin, o'zingizning maxsus tab bar va tab viewlaringizni ham yarata olasiz. Ammo shu standart TabView, va uni shunchalik oson joriy etish imkoniyati — bizga dasturchi sifatida juda yordam beradi.
Mana shu — ushbu video uchun shu qadar. Har doimgidek, men — Nick, bu Swiftful Thinking, va keyingi videoda ko'rishamiz!