Published on

Netflix kloni (3-qism): Gorizontal ro'yxatlar va Top 10 reytingi

Authors

1. Oddiy kino katakchasi (Netflix movie cell)

Netflixning asosiy qismida qator-qator turli xil kinolar rasmi joylashgan bo'ladi. Ular ba'zan o'ziga xos "Recently Added" (Yaqinda qo'shilgan) kabi maxsus qizil belgilarga ega bo'ladi. Avval shu bitta katakchani yasab olamiz.

import SwiftUI

struct NetflixMovieCell: View {
    var width: CGFloat = 90
    var height: CGFloat = 140
    var imageName: String = "https://picsum.photos/600/600"
    var title: String? = "Movie Title"
    var isRecentlyAdded: Bool = false
    var top10Ranking: Int? = nil // Agar nil bo'lmasa, Top 10 raqamini chizamiz

    var body: some View {
        HStack(alignment: .bottom, spacing: -8) {
            // Agar Top 10 reytingi bo'lsa, chap tomonda katta raqam chiziladi
            if let top10Ranking {
                Text("\(top10Ranking)")
                    .font(.system(size: 100, weight: .medium, design: .serif))
                    .offset(y: 20) // Raqamni biroz pastga tushiramiz
            }

            ZStack(alignment: .bottom) {
                ImageLoaderView(urlString: imageName)

                VStack(spacing: 0) {
                    if let title {
                        // Kichik katakchaga faqat birinchi so'zni yozamiz
                        Text(title.components(separatedBy: " ").first ?? title)
                            .font(.subheadline)
                            .fontWeight(.medium)
                            .lineLimit(1)
                    }

                    Text("Recently Added")
                        .padding(.horizontal, 4)
                        .padding(.vertical, 2)
                        .background(Color.netflixRed)
                        .cornerRadius(2)
                        .offset(y: 2)
                        .font(.caption2)
                        .fontWeight(.bold)
                        .minimumScaleFactor(0.1)
                        // Boshqa hujayralar bilan bir xil balandlikda turishi uchun opacity ishlatamiz
                        .opacity(isRecentlyAdded ? 1 : 0)
                }
                .padding(.horizontal, 8)
                .background(
                    LinearGradient(
                        colors: [.netflixBlack.opacity(0), .netflixBlack.opacity(0.4)],
                        startPoint: .top,
                        endPoint: .bottom
                    )
                )
            }
            .frame(width: width, height: height)
        }
        .foregroundColor(.netflixWhite)
    }
}

Qiziqarli yondashuv (Opacity vs If): Nega biz if isRecentlyAdded demasdan uning o'rniga .opacity() ni ishlatdik? Chunki, gorizontal ro'yxatda yonma-yon turgan katakchalarda birida yozuv bo'lib, boshqasida bo'lmasa, ularning tepasidagi kino nomlari (Title) past-baland bo'lib qoladi. Yozuv doim u yerda bo'lib, faqat ko'rinmas (Opacity = 0) qilib qo'yish orqali biz barcha nomlarning bir xil tekislikda turishini ta'minladik.

2. Katta Raqamli "Top 10" effekti

Yuqoridagi kodga e'tibor qaratsangiz, biz katta 1 dan 10 gacha bo'lgan reyting raqamlari uchun rasmning orqasiga kirib turuvchi dizaynni ishlatdik. Buning siri — HStack(spacing: -8). Manfiy (negative) oraliq masofa qo'llash orqali biz Chap tomondagi raqamni rasmning ustiga (yoki ortiga) biroz qoplatishimiz mumkin. Raqamga berilgan .serif shrift dizayni esa xuddi Netflixdagi kabi rasmiy va chiroyli ko'rinish beradi.

3. Qatorlarni yig'ish (Category Rows)

Endi barcha qatorlarni NetflixHomeView ekraniga joylashtiramiz.

@State private var productRows: [ProductRow] = []

// Asosiy ScrollView ichida:
LazyVStack(spacing: 16) {
    // Array va .enumerated() orqali nechanchi qator ekanligini aniqlaymiz
    ForEach(Array(productRows.enumerated()), id: \.offset) { rowIndex, row in
        VStack(alignment: .leading, spacing: 6) {
            Text(row.title)
                .font(.headline)
                .padding(.horizontal, 16)

            ScrollView(.horizontal, showsIndicators: false) {
                LazyHStack {
                    ForEach(Array(row.products.enumerated()), id: \.offset) { index, product in
                        NetflixMovieCell(
                            imageName: product.image,
                            title: product.title,
                            isRecentlyAdded: product.recentlyAdded,
                            // Faqatgina 2-qator (index == 1) ni Top 10 qilib ko'rsatamiz
                            top10Ranking: rowIndex == 1 ? (index + 1) : nil
                        )
                    }
                }
                .padding(.horizontal, 16)
            }
        }
    }
}

E'tibor bergan bo'lsangiz, biz barcha qatorlarni emas, faqatgina ikkinchi qatorni (rowIndex == 1) Top 10 ro'yxati deb belgiladik.

Bu darsimizda UI (User Interface) ni qanday qilib arxitektura jihatidan qismlarga bo'lish muhimligini yana bir bor ko'rdik. Keyingi qismda eng qiziqarli narsalardan biri — tepaga skroll qilganda Header'ning o'zgarishi va qorayib ketishi (Scroll Offset Animations) ni ko'rib chiqamiz.

Buy mea coffee