Published on

SwiftUI crypto app — SwiftUI Shape yordamida chiziqli grafik yaratish

Authors

SwiftUI crypto app — SwiftUI Shape yordamida chiziqli grafik yaratish

Bu dars butun kursning eng qiyin darslaridan biri. Matematik hisoblar bor, lekin men barchasi qadamma-qadam tushuntiraman. Biz so'nggi 7 kun narxlari uchun chiroyli chiziqli grafik yaratamiz — va uning rangi narx o'sgan bo'lsa yashil, tushgan bo'lsa qizil bo'ladi.


1. Sparkline ma'lumotlari

CoinModel-da sparklineIn7D.price — 168 ta raqamdan iborat array (7 kun × 24 soat). Bu — grafigimizdagi y-koordinata manbalari.

// coin.sparklineIn7D?.price -> [Double]
// Masalan: [54000, 53800, 55200, ...]

2. ChartView yaratish

core/detail/views papkasida ChartView.swift:

struct ChartView: View {
    private let data: [Double]
    private let maxY: Double
    private let minY: Double
    private let lineColor: Color
    private let startingDate: Date
    private let endingDate: Date

    init(coin: CoinModel) {
        data = coin.sparklineIn7D?.price ?? []
        maxY = data.max() ?? 0
        minY = data.min() ?? 0

        // Narx oshganmi yoki tushganmi?
        let priceChange = (data.last ?? 0) - (data.first ?? 0)
        lineColor = priceChange > 0 ? Color.theme.green : Color.theme.red

        endingDate = Date(coinGeckoString: coin.lastUpdated ?? "")
        startingDate = endingDate.addingTimeInterval(-7 * 24 * 60 * 60)  // 7 kun orqaga
    }

    var body: some View {
        VStack {
            chartView
                .frame(height: 200)
                .background(chartBackground)
                .overlay(chartYAxis, alignment: .leading)

            // Pastki sana belgilari
            chartDateLabels
                .padding(.horizontal, 4)
        }
        .font(.caption)
        .foregroundColor(Color.theme.secondaryText)
    }
}

3. Path va GeometryReader — grafikni chizish

Grafik koordinata tizimi tushuntirilishi:

iPhone ekranida (0, 0) nuqta yuqori chap burchak. Y qiymati pastga tomon oshadi. Shu sababli matematik formulada teskari yo'nalish kerak.

private var chartView: some View {
    GeometryReader { geometry in
        // Y-o'q diapazoni
        let yAxis = maxY - minY

        Path { path in
            for index in data.indices {

                // X koordinata: ekran kengligi / ma'lumotlar soni × indeks
                let xPosition = geometry.size.width / CGFloat(data.count) * CGFloat(index + 1)

                // Y koordinata hisoblash:
                // 1. Ma'lumot nuqtasining minimumdan farqi
                // 2. Y o'qiga nisbatan ulushi (foiz)
                // 3. Grafikning haqiqiy balandligiga ko'paytirish
                // 4. 1 - ni ayirish (iPhone koordinatasi teskari)
                let yPosition = (1 - CGFloat((data[index] - minY) / yAxis)) * geometry.size.height

                if index == 0 {
                    path.move(to: CGPoint(x: xPosition, y: yPosition))
                }
                path.addLine(to: CGPoint(x: xPosition, y: yPosition))
            }
        }
        .stroke(
            lineColor,
            style: StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round)
        )
    }
}

Matematik misol: Bitcoin maksimali 60,000,minimali50,000, minimali 50,000. Y-o'q = 10,000. Qiymat 52,000$ bo'lsa:

  • Minimumdan farq: 52,000 - 50,000 = 2,000
  • Foiz: 2,000 / 10,000 = 0.2 (20%)
  • Teskari: 1 - 0.2 = 0.8 (80% pastdan, ya'ni yuqoridan 20%)
  • Balandligi 200px bo'lsa: 0.8 × 200 = 160px (tepadan)

4. Fon grid chiziqlari

Grafikni "professional" ko'rinishga keltirish uchun orqa fonda uch qatorda gorizontal chiziqlar:

private var chartBackground: some View {
    VStack {
        Divider()
        Spacer()
        Divider()
        Spacer()
        Divider()
    }
}

5. Y-o'q belgilari (eng yuqori, o'rta, eng past narx)

private var chartYAxis: some View {
    VStack {
        Text(maxY.formattedWithAbbreviations())  // Masalan: $58K
        Spacer()
        Text(((maxY + minY) / 2).formattedWithAbbreviations())  // O'rta narx
        Spacer()
        Text(minY.formattedWithAbbreviations())  // Masalan: $52K
    }
}

6. Pastki sana belgilari

private var chartDateLabels: some View {
    HStack {
        Text(startingDate.asShortDateString())  // "Dec 3"
        Spacer()
        Text(endingDate.asShortDateString())    // "Dec 10"
    }
}

Date+Extensions.swift-da:

// CoinGecko formatidan Date ga aylantirish
init(coinGeckoString: String) {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
    let date = formatter.date(from: coinGeckoString) ?? Date()
    self.init(timeInterval: 0, since: date)
}

// Qisqa ko'rinish
func asShortDateString() -> String {
    return self.formatted(.dateTime.month().day().year())
}

7. DetailView-ga ChartView qo'shish

DetailView-dagi bo'sh Text("") o'rniga:

var body: some View {
    ScrollView {
        VStack {
            // Grafik — yuqori bo'lim
            ChartView(coin: vm.coin)
                .padding(.vertical)

            VStack(spacing: 20) {
                // ... statistika va tavsif
            }
            .padding()
        }
    }
}

8. Animatsiya qo'shish

Grafik ekranda paydo bo'lganda chizilish animatsiyasini qo'shish:

// ChartView ichida:
@State private var percentage: CGFloat = 0

// Path stroke-ni trim bilan:
.trim(from: 0, to: percentage)

// onAppear-da:
.onAppear {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
        withAnimation(.linear(duration: 2.0)) {
            percentage = 1.0
        }
    }
}

trim(from:to:) — path-ning qancha qismini ko'rsatishni belgilaydi. 0 dan 1 gacha animatsiya qilsak — grafik chap tomondancha o'ngga chiziladi.


Natija

Bitcoin detail ekraniga o'tsangiz:

  • Agar 7 kun ichida narx oshgan bo'lsa — yashil chiziq
  • Agar tushgan bo'lsa — qizil chiziq
  • Yuqorida, o'rtada, pastda narx belgilari
  • Pastda boshlash va tugash sanalari
  • Ekranga kirganda chap-o'ng chizilish animatsiyasi

"Bu grafik — to'liq SwiftUI Path va GeometryReader bilan qurilgan. Tashqi kutubxona yoki Chart framework ishlatilmagan. Bu naqadar kuchli!"

Keyingi darsda tavsifni kengaytiriladigan/qisqartiriladigan qilish va sozlamalar ekranini qo'shamiz. 🚀

Buy mea coffee