Published on

SwiftUI crypto app — statistika uchun model va view yaratish

Authors

SwiftUI crypto app — statistika uchun model va view yaratish

Bu darsda biz ilovaning bosh ekrani yuqori qismida ko'rinadigan statistika bo'limini yaratamiz. U global kriptovalyuta bozorining ma'lumotlarini — bozor kapitalizatsiyasi, 24 soatlik savdo hajmi, Bitcoin ulushi va foydalanuvchi portfelining qiymatini ko'rsatadi. Hozircha view va model tuzamiz, ma'lumotlar esa keyingi darsda API dan olinadi.


1. StatisticModel — statistika uchun model

Avval models papkasida StatisticModel.swift faylini yarataymiz. Har bir statistika elementi — kichik bir kartochka bo'lib, u sarlavha, asosiy qiymat va ixtiyoriy foiz o'zgarishidan iborat:

import Foundation

struct StatisticModel: Identifiable {

    // Identifiable protokoli uchun id — ForEach da ishlash uchun
    let id: String
    let title: String      // Masalan: "Bozor kapitalizatsiyasi"
    let value: String      // Masalan: "$1.23T"
    let percentageChange: Double?  // Ixtiyoriy — ba'zi kartochkalarda foiz bo'lmaydi

    // Maxsus init: percentageChange uchun default qiymat = nil
    init(title: String, value: String, percentageChange: Double? = nil) {
        self.id = UUID().uuidString  // Har safar yangi tasodifiy ID
        self.title = title
        self.value = value
        self.percentageChange = percentageChange
    }
}

percentageChange-ga = nil default qiymati berish orqali bu parametrni ixtiyoriy qilamiz. Endi StatisticModel(title: "Hajm", value: "$1.2T") deb ham yarataversa bo'ladi.


2. StatisticView — bitta statistika kartochkasi

components papkasida StatisticView.swift nomli SwiftUI view yaratamiz. Bu view bitta statistika modelini qabul qiladi va uni chiroyli ko'rsatadi:

import SwiftUI

struct StatisticView: View {

    let stat: StatisticModel

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {

            // Sarlavha — kichik kulrang matn
            Text(stat.title)
                .font(.caption)
                .foregroundColor(Color.theme.secondaryText)

            // Asosiy qiymat — qalin matn
            Text(stat.value)
                .font(.headline)
                .foregroundColor(Color.theme.accent)

            // Foiz o'zgarishi — o'q va raqam (agar mavjud bo'lsa ko'rinadi)
            HStack(spacing: 4) {
                Image(systemName: "triangle.fill")
                    .font(.caption2)
                    // Foiz musbat bo'lsa — yuqoriga, manfiy bo'lsa — pastga buriladi
                    .rotationEffect(
                        Angle(degrees: (stat.percentageChange ?? 0) >= 0 ? 0 : 180)
                    )

                Text(stat.percentageChange?.asPercentString() ?? "")
                    .font(.caption)
                    .bold()
            }
            // Foiz musbat — yashil, manfiy — qizil
            .foregroundColor(
                (stat.percentageChange ?? 0) >= 0 ? Color.theme.green : Color.theme.red
            )
            // Foiz bo'lmasa — yashiramiz, lekin joy band qolaveradi (alignment uchun)
            .opacity(stat.percentageChange == nil ? 0.0 : 1.0)
        }
    }
}

Nima uchun opacity ishlatamiz if let o'rniga? Agar if let ishlatganda, foizi bo'lmagan kartochkalar balandligi qisqa bo'lardi — ular boshqalar bilan bir qatorda tura olmasdi. opacity: 0.0 esa elementni ekranda chizmaydi, lekin joyni band qiladi — barcha kartochkalar balandligi bir xil bo'ladi.


3. HomeStatsView — statistikalar qatori

home/views papkasida HomeStatsView.swift yaratamiz. Bu view statistika kartochkalarini gorizontal qator shaklida ko'rsatadi va showPortfolio holati bo'yicha animatsiya qiladi:

import SwiftUI

struct HomeStatsView: View {

    @EnvironmentObject private var vm: HomeViewModel

    // Tugma bosilganda portfelga o'tish animatsiyasi uchun
    @Binding var showPortfolio: Bool

    var body: some View {
        HStack {
            ForEach(vm.statistics) { stat in
                StatisticView(stat: stat)
                    // Har bir kartochka ekran kengligining 1/3 qismini oladi
                    .frame(width: UIScreen.main.bounds.width / 3)
            }
        }
        // Butun qatorning kengligi ekran kengligi bilan cheklangan
        .frame(width: UIScreen.main.bounds.width)
        // showPortfolio bo'lsa o'ngga, bo'lmasa chapga suriladi
        .frame(alignment: showPortfolio ? .trailing : .leading)
    }
}

Nima uchun UIScreen.main.bounds.width? Bu ilova faqat portrait rejimida ishlaydi, shuning uchun bu usul to'g'ri. Agar landscape ham bo'lganda GeometryReader ishlatilishi kerak edi.


4. HomeViewModel-ga statistics qo'shish

HomeViewModel.swift-ga @Published var statistics qo'shamiz:

class HomeViewModel: ObservableObject {
    @Published var statistics: [StatisticModel] = []
    @Published var allCoins: [CoinModel] = []
    @Published var portfolioCoins: [CoinModel] = []
    @Published var searchText: String = ""
    // ...
}

5. HomeView-ga HomeStatsView qo'shish

HomeView.swift-da qidiruv satridan oldin HomeStatsView-ni joylashtiramiz:

VStack {
    homeHeader

    // Statistika bo'limi — showPortfolio-ga bog'liq animatsiya bilan
    HomeStatsView(showPortfolio: $showPortfolio)

    // Qidiruv satri
    SearchBarView(searchText: $vm.searchText)

    columnTitles

    if !showPortfolio {
        allCoinsList
            .transition(.move(edge: .leading))
    }
    if showPortfolio {
        portfolioCoinsList
            .transition(.move(edge: .trailing))
    }

    Spacer(minLength: 0)
}

6. Sinash: animatsiya ishlayaptimi?

Simulatorda ilovani ishga tushiring. Yuqori o'ng tugmani bossangiz, statistika qatori chap tomonda ko'ringan holatdan o'ng tomonga (portfel qiymatiga) siljiydi. Bu oddiy alignment o'zgarishi orqali amalga oshirilgan — juda samarali va ajoyib ko'rinadi.

"Butun animatsiya — faqat frame-ning alignment-ini leadingdan trailing-ga o'zgartirish. SwiftUI qolganini o'zi amalga oshiradi. Mana bu SwiftUI-ning kuchi!"

Keyingi darsda biz API dan real bozor ma'lumotlarini yuklab olib, ushbu statistika bo'limini to'ldiramiz. 🚀

Buy mea coffee