- Published on
Netflix kloni (5-qism): Film haqida batafsil oyna (Details View)
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
Film oynasi arxitekturasi
Odatda oynadan oynaga o'tishda ekranni to'liq yangilash (Push) ishlatiladi. Lekin Netflixda biron filmni bossangiz, u pastdan qalqib chiquvchi oyna (Sheet) shaklida ochiladi. Bu foydalanuvchiga yana tezda orqaga qaytish imkonini beradi.
Ushbu oyna ikkita katta qismdan iborat bo'ladi:
- Header (Tepa qism): Rasm, kino progressi va yopish tugmasi (Skroll bo'lmaydi).
- Product (Asosiy qism): Kino nomi, reytingi, ta'rifi va tugmalar (Skroll bo'ladi).
1. Header qismini yasash
import SwiftUI
struct NetflixDetailsHeaderView: View {
var imageName: String = "https://picsum.photos/600/600"
var progress: Double = 0.2 // Kino qancha ko'rilgani (0 dan 1 gacha)
var onAirPlayPressed: (() -> Void)? = nil
var onXMarkPressed: (() -> Void)? = nil
var body: some View {
ZStack(alignment: .bottom) {
// Rasm (Aspect Ratio: 2:1)
ImageLoaderView(urlString: imageName)
.aspectRatio(2, contentMode: .fit)
// Kino progressi (Custom Progress Bar)
CustomProgressBar(
selection: progress,
range: 0...1,
backgroundColor: .netflixLightGray,
foregroundColor: .netflixRed,
cornerRadius: 2,
height: 4
)
.padding(.bottom, 4)
// Tepadagi tugmalar
HStack(spacing: 8) {
CircleButton(iconName: "tv.badge.wifi", action: onAirPlayPressed)
CircleButton(iconName: "xmark", action: onXMarkPressed)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
.padding(8)
}
}
}
// Qayta ishlatiladigan yumaloq tugma
struct CircleButton: View {
var iconName: String
var action: (() -> Void)?
var body: some View {
Image(systemName: iconName)
.font(.subheadline)
.fontWeight(.bold)
.foregroundColor(.netflixWhite)
.offset(y: 1) // Ba'zi iconlar markazdan qochmasligi uchun
.frame(width: 36, height: 36)
.background(Circle().fill(Color.netflixDarkGray))
.onTapGesture {
action?()
}
}
}
UI Dizayn siri: Nega default Apple
ProgressViewo'rniga o'zimizning progress bar ni ishlatmoqdamiz? Chunki Apple progress barida burchaklarni to'liq boshqarish qiyin. Netflix dagi progress barda esa chiziq ingichka (height 4) va uning har bir uchi yengil qayrilgan (Corner radius 2 - aynan balandlikning yarmi).
2. Meta-ma'lumotlar sahnasi (Product View)
Kino tasviri, uning nechanchi yilda chiqqani, sezonlar soni, va agar top 10 likda bo'lsa qizil nishon (Badge) qo'yiladi.
import SwiftUI
struct NetflixDetailsProductView: View {
var title: String = "Movie Title"
var isNew: Bool = true
var yearReleased: String? = "2024"
var seasonsCount: Int? = 2
var hasClosedCaptions: Bool = true
var isTop10: Int? = 6
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text(title)
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
HStack(spacing: 8) {
if isNew {
Text("New")
.foregroundColor(.green)
}
if let yearReleased {
Text(yearReleased)
}
if let seasonsCount {
Text("\(seasonsCount) Seasons")
}
if hasClosedCaptions {
Image(systemName: "captions.bubble")
}
}
.foregroundColor(.netflixLightGray)
// Top 10 Nishoni (Badge)
if let isTop10 {
HStack(spacing: 8) {
top10Icon
Text("#\(isTop10) in TV Shows Today")
.font(.headline)
}
}
// ... O'ynatish va Yuklab olish tugmalari ...
// ... Ta'rif va Aktyorlar (Cast) matni ...
}
.foregroundColor(.netflixWhite)
}
// Maxsus Top 10 nishoni
private var top10Icon: some View {
Rectangle()
.fill(Color.netflixRed)
.frame(width: 28, height: 28)
.overlay(
VStack(spacing: -4) { // So'zlarni bir biriga yopishtirish
Text("TOP")
.font(.system(size: 8, weight: .bold))
Text("10")
.font(.system(size: 16, weight: .bold))
}
.offset(y: 1)
)
}
}
Bu yerda biz barcha if-shartlarini to'g'ri ishlatdik. Ma'lumotlarni Backenddan olayotganda bizda ularning hammasi ham doim mavjud bo'lmaydi (masalan barcha kino ham yangi emas). Shuning uchun bunday komponentlarni qurishda Optional turlardan (masalan Int?) keng foydalanish juda muhim.
Navbatdagi, Netflix loyihamizning so'nggi darsida bu oyna ichidagi mayda, ko'zni quvnatadigan animatsiyalar bilan ishlashni yakunlaymiz!