# SnapKit 15: SwiftUI dan SnapKit ga Ko'prik — SwiftUI bilsang, SnapKit'ni 10x tez o'rganasan

> **Holat:** Ushbu dars 2026-yil oktabr holatiga ko'ra tayyorlangan. Agar siz SwiftUI'ni yaxshi bilsangiz, ushbu dars sizga SnapKit (va umuman UIKit layout) qanday ishlashini SwiftUI analoglari orqali juda tez o'rganishga yordam beradi.

## Mundarija
1. [VStack → Vertikal Layout](#vstack)
2. [HStack → Gorizontal Layout](#hstack)
3. [ZStack → Ustma-ust qo'yish (Layering)](#zstack)
4. [.padding() → inset/offset](#padding)
5. [.frame(width:height:) → size constraints](#frame)
6. [.background() / .overlay() → background va overlay view](#background)
7. [Spacer() → Bo'sh joy](#spacer)
8. [.cornerRadius / .clipShape → layer.cornerRadius](#cornerradius)
9. [.shadow → layer.shadow](#shadow)
10. [ScrollView → UIScrollView](#scrollview)
11. [List → UITableView](#list)
12. [@State / Animation → Constraint Animation](#animation)
13. [GeometryReader → layoutSubviews / bounds](#geometryreader)
14. [NavigationStack → UINavigationController](#navigationstack)
15. [KATTA AMALIY LOYIHA 1: Profil ekrani](#loyiha1)
16. [KATTA AMALIY LOYIHA 2: Product Card](#loyiha2)
17. [SwiftUI vs SnapKit: Qachon qaysi biri?](#qachon)
18. [Xulosa](#xulosa)
19. [Manbalar](#manbalar)

---

## 1. VStack → Vertikal Layout {#vstack}

SwiftUI'da elementlarni vertikal joylashtirish uchun `VStack` ishlatamiz. SnapKit'da buning eng yaqin ekvivalenti `UIStackView(.vertical)` hisoblanadi. Yoki to'liq moslashuvchanlik uchun barcha constraint'larni o'zimiz yozishimiz mumkin.

### SwiftUI'da:
```swift
VStack(spacing: 16) {
    Text("Salom")
    Button("Bosing") {}
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

**1-usul: UIStackView (Tavsiya etiladi)**
```swift
import UIKit
import SnapKit

class VstackViewController: UIViewController {
    let titleLabel = UILabel()
    let actionButton = UIButton(type: .system)
    
    // VStack ekvivalenti
    lazy var vStack: UIStackView = {
        let stack = UIStackView(arrangedSubviews: [titleLabel, actionButton])
        stack.axis = .vertical
        stack.spacing = 16
        stack.alignment = .center // SwiftUI'dagi VStack alignment'i kabi
        return stack
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        titleLabel.text = "Salom"
        actionButton.setTitle("Bosing", for: .normal)
        
        view.addSubview(vStack)
        
        vStack.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
    }
}
```

**2-usul: Manual Constraints (SnapKit orqali, StackView'siz)**
```swift
// Elementlarni to'g'ridan to'g'ri view'ga qo'shamiz
view.addSubview(titleLabel)
view.addSubview(actionButton)

titleLabel.snp.makeConstraints { make in
    make.centerX.equalToSuperview()
    make.centerY.equalToSuperview().offset(-16) // Markazdan sal teparoqda
}

actionButton.snp.makeConstraints { make in
    make.centerX.equalToSuperview()
    make.top.equalTo(titleLabel.snp.bottom).offset(16) // spacing: 16
}
```

---

## 2. HStack → Gorizontal Layout {#hstack}

Xuddi VStack kabi, `HStack` ham `UIStackView` yordamida (axis = .horizontal) yoki manual constraint'lar orqali amalga oshiriladi.

### SwiftUI'da:
```swift
HStack(spacing: 12) {
    Image(systemName: "star")
    Text("Reyting")
    Spacer()
    Button("Ko'rish") {}
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
import UIKit
import SnapKit

class HstackViewController: UIViewController {
    let iconImageView = UIImageView(image: UIImage(systemName: "star"))
    let titleLabel = UILabel()
    let actionButton = UIButton(type: .system)
    
    lazy var hStack: UIStackView = {
        let stack = UIStackView(arrangedSubviews: [iconImageView, titleLabel, UIView(), actionButton])
        stack.axis = .horizontal
        stack.spacing = 12
        stack.alignment = .center
        return stack
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        titleLabel.text = "Reyting"
        actionButton.setTitle("Ko'rish", for: .normal)
        
        // Spacer() vazifasini stack.arrangedSubviews ichidagi UIView() bajaradi!
        // U bo'sh joyni egallaydi.
        
        view.addSubview(hStack)
        
        hStack.snp.makeConstraints { make in
            make.left.right.equalToSuperview().inset(16)
            make.centerY.equalToSuperview()
        }
    }
}
```

---

## 3. ZStack → Ustma-ust qo'yish (Layering) {#zstack}

SwiftUI'da `ZStack` elementlarni bir-birining ustiga qo'yadi (z-order). Oxirgi qo'shilgan element eng tepada turadi. SnapKit'da buni qilish juda oson: biz elementlarni bitta parent view'ga ketma-ket `addSubview()` qilamiz va hammasining chegaralarini (`edges`) bir xil qilib belgilaymiz.

### SwiftUI'da:
```swift
ZStack {
    Image("background")
    LinearGradient(colors: [.black.opacity(0.5), .clear], startPoint: .bottom, endPoint: .top)
    Text("Sarlavha")
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
let backgroundImageView = UIImageView(image: UIImage(named: "background"))
let gradientView = UIView()
let titleLabel = UILabel()

titleLabel.text = "Sarlavha"

// 1. Qo'shish tartibi Z-ordering'ni bildiradi
// Eng birinchi qo'shilgan eng orqada bo'ladi.
view.addSubview(backgroundImageView)
view.addSubview(gradientView)
view.addSubview(titleLabel)

backgroundImageView.snp.makeConstraints { make in
    make.edges.equalToSuperview()
}

gradientView.snp.makeConstraints { make in
    make.edges.equalToSuperview()
}

titleLabel.snp.makeConstraints { make in
    make.center.equalToSuperview()
}
```

---

## 4. .padding() → inset/offset {#padding}

SwiftUI'da `.padding()` o'zi turgan joydan ichkariga joy tashlaydi. SnapKit'da esa buning uchun asosan `offset()` va `inset()` ishlatamiz. 

### SwiftUI'da:
```swift
Text("Salom")
    .padding(16) // Barcha tarafdan
    .padding(.horizontal, 20) // Faqat chap va o'ngdan
    .padding(.top, 32) // Faqat tepadan
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
let containerView = UIView()
let titleLabel = UILabel()
containerView.addSubview(titleLabel)

// .padding(16) ga ekvivalent:
titleLabel.snp.makeConstraints { make in
    make.edges.equalToSuperview().inset(16)
}

// .padding(.horizontal, 20) ga ekvivalent:
titleLabel.snp.makeConstraints { make in
    make.leading.trailing.equalToSuperview().inset(20)
    make.top.bottom.equalToSuperview() // boshqa taraflar padding'siz
}

// .padding(.top, 32) ga ekvivalent:
titleLabel.snp.makeConstraints { make in
    make.top.equalToSuperview().offset(32)
    // qolganlari ...
}
```

> **Muhim:** `offset` va `inset` farqi. Bottom va trailing uchun `offset` manfiy bo'lishi kerak. Ammo `inset` orqali berilsa, doim musbat son yoziladi (ichkariga siqish).
> JADVAL: 
> - `.padding(.top, N)` = `make.top.offset(N)`
> - `.padding(.bottom, N)` = `make.bottom.inset(N)` (Yoki `offset(-N)`)
> - `.padding(.leading, N)` = `make.leading.offset(N)`
> - `.padding(.trailing, N)` = `make.trailing.inset(N)` (Yoki `offset(-N)`)

---

## 5. .frame(width:height:) → size constraints {#frame}

SwiftUI'dagi `.frame` orqali width/height beriladi. SnapKit'da esa buning uchun `width`, `height`, va `size` ishlatiladi.

### SwiftUI'da:
```swift
Color.red
    .frame(width: 200, height: 100)
    .frame(maxWidth: .infinity)
    .frame(minHeight: 44)
    .frame(maxWidth: 300)
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
let redView = UIView()
redView.backgroundColor = .red
view.addSubview(redView)

redView.snp.makeConstraints { make in
    // .frame(width: 200, height: 100)
    make.size.equalTo(CGSize(width: 200, height: 100))
    // yoki: make.width.equalTo(200); make.height.equalTo(100)
    
    // .frame(maxWidth: .infinity) -> Parent'ni to'ldirish
    make.width.equalToSuperview() 
    
    // .frame(minHeight: 44)
    make.height.greaterThanOrEqualTo(44)
    
    // .frame(maxWidth: 300)
    make.width.lessThanOrEqualTo(300)
}
```

---

## 6. .background() / .overlay() → background va overlay view {#background}

SwiftUI'da element orqasiga `.background()` bilan, ustiga `.overlay()` bilan view qo'shamiz. UIKit'da `.backgroundColor` ishlatish mumkin yoki yana ZStack logikasiga o'xshab view'lar tartibi bilan hal qilinadi.

### SwiftUI'da:
```swift
Text("Salom")
    .background(Color.blue)
    
Text("Salom")
    .background(RoundedRectangle(cornerRadius: 8).fill(.blue))
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
let titleLabel = UILabel()
titleLabel.text = "Salom"

// 1-usul: Oddiy rang (Faqat shu element o'zi)
titleLabel.backgroundColor = .systemBlue

// 2-usul: Alohida View (Masalan rasm yoki gradient qo'ymoqchi bo'lsangiz)
let backgroundView = UIView()
backgroundView.backgroundColor = .systemBlue
backgroundView.layer.cornerRadius = 8

view.addSubview(backgroundView)
view.addSubview(titleLabel) // titleLabel tepada

titleLabel.snp.makeConstraints { make in
    make.center.equalToSuperview()
}

// BackgroundView titleLabel bilan bir xil o'lcham va joylashuvga ega bo'ladi
backgroundView.snp.makeConstraints { make in
    make.edges.equalTo(titleLabel).inset(-8) // Atrofiga biroz padding qo'shish
}
```

---

## 7. Spacer() → Bo'sh joy {#spacer}

SwiftUI'da `Spacer()` moslashuvchan bo'sh joy yaratadi. UIKit'da buning 3 xil ekvivalenti bor.

### SwiftUI'da:
```swift
HStack {
    Text("Chapda")
    Spacer()
    Text("O'ngda")
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

**a) UIView() spacer (Eng oson, UIStackView bilan):**
```swift
let hStack = UIStackView(arrangedSubviews: [leftLabel, UIView(), rightLabel])
hStack.axis = .horizontal
// UIView() avtomatik bo'shliqni egallaydi.
```

**b) UILayoutGuide (Xotira tejamkor):**
Agar stackView ishlatmasangiz, bo'sh UIView o'rniga `UILayoutGuide` ishlating, chunki u ekranda render bo'lmaydi.
```swift
let spacerGuide = UILayoutGuide()
view.addLayoutGuide(spacerGuide)

view.addSubview(leftLabel)
view.addSubview(rightLabel)

leftLabel.snp.makeConstraints { make in
    make.left.equalToSuperview()
    make.right.equalTo(spacerGuide.snp.left)
}

spacerGuide.snp.makeConstraints { make in
    make.right.equalTo(rightLabel.snp.left)
    // spacer o'ziga qarab cho'ziladi
}

rightLabel.snp.makeConstraints { make in
    make.right.equalToSuperview()
}
```

**c) Content Hugging Priority (Advanced):**
```swift
view.addSubview(leftLabel)
view.addSubview(rightLabel)

// rightLabel ni o'ngga yopishtiramiz, leftLabel chapga. O'rtadagi masofa avtomatik ochiladi.
leftLabel.snp.makeConstraints { make in
    make.left.equalToSuperview()
    make.right.lessThanOrEqualTo(rightLabel.snp.left)
}

rightLabel.snp.makeConstraints { make in
    make.right.equalToSuperview()
}

// Chapdagi label siqilmasligi uchun, o'ngdagiga ustunlik beramiz
rightLabel.setContentHuggingPriority(.required, for: .horizontal)
```

---

## 8. .cornerRadius / .clipShape → layer.cornerRadius {#cornerradius}

### SwiftUI'da:
```swift
Image("profile")
    .cornerRadius(12)
    
Image("profile")
    .clipShape(Circle())
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
let profileImageView = UIImageView(image: UIImage(named: "profile"))
profileImageView.clipsToBounds = true // SwiftUI'dagi kabi qirqilishi uchun muhim!

// .cornerRadius(12)
profileImageView.layer.cornerRadius = 12

// .clipShape(Circle()) (O'lchami 80x80 deb faraz qilsak)
profileImageView.snp.makeConstraints { make in
    make.size.equalTo(80)
}
profileImageView.layer.cornerRadius = 40 // width / 2
```

---

## 9. .shadow → layer.shadow {#shadow}

Shadow berish SwiftUI'da juda oson, UIKit'da esa biroz ko'proq kod yoziladi.

### SwiftUI'da:
```swift
Color.white
    .shadow(color: .black.opacity(0.2), radius: 8, x: 0, y: 4)
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
let cardView = UIView()
cardView.backgroundColor = .white

// .shadow ekvivalenti
cardView.layer.shadowColor = UIColor.black.cgColor
cardView.layer.shadowOpacity = 0.2
cardView.layer.shadowRadius = 8
cardView.layer.shadowOffset = CGSize(width: 0, height: 4)

// MUHIM: Shadow ko'rinishi uchun clipsToBounds false bo'lishi kerak!
cardView.clipsToBounds = false 
```

---

## 10. ScrollView → UIScrollView {#scrollview}

ScrollView UIKit'da SwiftUI'ga qaraganda birmuncha murakkabroq ishlaydi, chunki unda `contentSize` tushunchasi bor. SnapKit bilan buni oson qilish mumkin (contentView yaratish).

### SwiftUI'da:
```swift
ScrollView {
    VStack {
        Text("Tepa")
        // ... ko'p elementlar
        Text("Past")
    }
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
let scrollView = UIScrollView()
let contentView = UIView() // Barcha elementlar shunga tushadi
let topLabel = UILabel()
let bottomLabel = UILabel()

view.addSubview(scrollView)
scrollView.addSubview(contentView)
contentView.addSubview(topLabel)
contentView.addSubview(bottomLabel)

// 1. ScrollView ekranni to'ldiradi
scrollView.snp.makeConstraints { make in
    make.edges.equalToSuperview()
}

// 2. ContentView ScrollView'ning content'ini belgilaydi
contentView.snp.makeConstraints { make in
    make.edges.equalToSuperview() // Content hajmiga mos
    make.width.equalTo(scrollView) // Vertikal scroll qilish uchun width'ni scrollView'ga tenglaymiz (X o'qida scroll yo'q)
}

// 3. Ichki elementlarni contentView ga yopishtiramiz
topLabel.snp.makeConstraints { make in
    make.top.left.right.equalToSuperview().inset(20)
}

bottomLabel.snp.makeConstraints { make in
    make.top.equalTo(topLabel.snp.bottom).offset(1000) // Juda uzoq
    make.left.right.equalToSuperview().inset(20)
    make.bottom.equalToSuperview().inset(20) // MUHIM: contentView'ning bottom'ini belgilash!
}
```

---

## 11. List → UITableView {#list}

SwiftUI'da `List` barcha ishlarni o'zi bajaradi. UIKit'da buning uchun `UITableView` (yoki `UICollectionView`) ishlatamiz.

### SwiftUI'da:
```swift
List {
    ForEach(items) { item in
        Text(item.name)
    }
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
// Controller ichida
let tableView = UITableView()
view.addSubview(tableView)

tableView.snp.makeConstraints { make in
    make.edges.equalToSuperview()
}

// Cell dizayni
class CustomCell: UITableViewCell {
    let titleLabel = UILabel()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        // MUHIM: Har doim contentView.addSubview ishlatiladi!
        contentView.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(16)
        }
    }
    
    required init?(coder: NSCoder) { fatalError() }
}
```

---

## 12. @State / Animation → Constraint Animation {#animation}

SwiftUI'da constraint'lar o'rniga holat (State) o'zgarishi kifoya. UIKit'da biz constraint referensini saqlab, uni o'zgartiramiz va `layoutIfNeeded()` chaqiramiz.

### SwiftUI'da:
```swift
@State var isExpanded = false

Color.blue
    .frame(height: isExpanded ? 200 : 80)
    .animation(.spring(), value: isExpanded)
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
import SnapKit

let boxView = UIView()
var heightConstraint: Constraint? // Constraint'ni saqlab qo'yamiz

boxView.backgroundColor = .blue
view.addSubview(boxView)

boxView.snp.makeConstraints { make in
    make.center.equalToSuperview()
    make.width.equalTo(100)
    // Referensni saqlash:
    self.heightConstraint = make.height.equalTo(80).constraint
}

// Animatsiyani trigger qilish
@objc func toggleSize() {
    let isExpanded = (boxView.bounds.height > 100)
    let newHeight = isExpanded ? 80 : 200
    
    // 1. Constraint'ni yangilash
    heightConstraint?.update(offset: newHeight)
    
    // 2. Animatsiya bilan layout'ni qayta chizish
    UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8) {
        self.view.layoutIfNeeded() // UIKit shu buyruq orqali animatsiya qiladi!
    }
}
```

---

## 13. GeometryReader → layoutSubviews / bounds {#geometryreader}

GeometryReader orqali view'ning o'zini hajmini bilib, shunga qarab boshqa narsalarga o'lcham beramiz. SnapKit buni asosan `multipliedBy` va UIKit ning `layoutSubviews` funksiyasi bilan qoplaydi.

### SwiftUI'da:
```swift
GeometryReader { geo in
    Color.red
        .frame(width: geo.size.width * 0.5) // Ekranning yarmi
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
// SnapKit usuli:
let redBox = UIView()
redBox.backgroundColor = .red
view.addSubview(redBox)

redBox.snp.makeConstraints { make in
    make.height.equalTo(100)
    // Ekranning (parent viewning) yarmi:
    make.width.equalToSuperview().multipliedBy(0.5) 
}

// Yoki aniq o'lcham kerak bo'lganda (UIKit standard):
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let parentWidth = view.bounds.width
    print("Mening o'lchamim endi ma'lum: \(parentWidth)")
}
```

---

## 14. NavigationStack → UINavigationController {#navigationstack}

### SwiftUI'da:
```swift
NavigationStack {
    VStack { ... }
    .navigationTitle("Asosiy")
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

```swift
// SceneDelegate yoki AppDelegate ichida:
let mainVC = MainViewController()
mainVC.title = "Asosiy"
let navController = UINavigationController(rootViewController: mainVC)
window?.rootViewController = navController
```

---

## 15. KATTA AMALIY LOYIHA 1: Profil ekrani {#loyiha1}

Bu yerda siz har ikki texnologiya o'rtasidagi to'liq ekvivalentlikni amalda ko'rasiz.

### SwiftUI'da (qisqa va aniq):
```swift
struct ProfileView: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                Image("avatar")
                    .resizable()
                    .frame(width: 80, height: 80)
                    .clipShape(Circle())
                
                Text("Azimjon")
                    .font(.system(size: 24, weight: .bold))
                
                Text("iOS Dasturchi. Kod yozaman va qahva ichaman.")
                    .foregroundColor(.gray)
                    .multilineTextAlignment(.center)
                    .padding(.horizontal, 32)
                
                HStack(spacing: 30) {
                    VStack { Text("120").bold(); Text("Posts") }
                    VStack { Text("4K").bold(); Text("Followers") }
                    VStack { Text("120").bold(); Text("Following") }
                }
                .padding(.top, 16)
                
                Button(action: {}) {
                    Text("Edit Profile")
                        .foregroundColor(.white)
                        .frame(maxWidth: .infinity)
                        .padding()
                        .background(Color.blue)
                        .cornerRadius(8)
                }
                .padding(.horizontal, 32)
                .padding(.top, 24)
            }
            .padding(.top, 40)
        }
    }
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz (to'liq kontrol):
```swift
import UIKit
import SnapKit

class ProfileViewController: UIViewController {
    
    // View'larni e'lon qilish
    let scrollView = UIScrollView()
    let contentView = UIView()
    
    let avatarImageView: UIImageView = {
        let img = UIImageView()
        img.backgroundColor = .systemGray4
        img.layer.cornerRadius = 40
        img.clipsToBounds = true
        return img
    }()
    
    let nameLabel: UILabel = {
        let lbl = UILabel()
        lbl.text = "Azimjon"
        lbl.font = .systemFont(ofSize: 24, weight: .bold)
        return lbl
    }()
    
    let bioLabel: UILabel = {
        let lbl = UILabel()
        lbl.text = "iOS Dasturchi. Kod yozaman va qahva ichaman."
        lbl.textColor = .gray
        lbl.numberOfLines = 0
        lbl.textAlignment = .center
        return lbl
    }()
    
    lazy var statsStack: UIStackView = {
        let postsStack = createStatStack(count: "120", title: "Posts")
        let followersStack = createStatStack(count: "4K", title: "Followers")
        let followingStack = createStatStack(count: "120", title: "Following")
        
        let stack = UIStackView(arrangedSubviews: [postsStack, followersStack, followingStack])
        stack.axis = .horizontal
        stack.spacing = 30
        stack.alignment = .center
        return stack
    }()
    
    let editButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Edit Profile", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.backgroundColor = .systemBlue
        btn.layer.cornerRadius = 8
        return btn
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        setupViews()
        setupConstraints()
    }
    
    func createStatStack(count: String, title: String) -> UIStackView {
        let countLbl = UILabel()
        countLbl.text = count
        countLbl.font = .boldSystemFont(ofSize: 16)
        
        let titleLbl = UILabel()
        titleLbl.text = title
        titleLbl.font = .systemFont(ofSize: 14)
        
        let stack = UIStackView(arrangedSubviews: [countLbl, titleLbl])
        stack.axis = .vertical
        stack.alignment = .center
        return stack
    }
    
    func setupViews() {
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)
        
        contentView.addSubview(avatarImageView)
        contentView.addSubview(nameLabel)
        contentView.addSubview(bioLabel)
        contentView.addSubview(statsStack)
        contentView.addSubview(editButton)
    }
    
    func setupConstraints() {
        scrollView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalTo(scrollView)
        }
        
        avatarImageView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(40)
            make.centerX.equalToSuperview()
            make.size.equalTo(80)
        }
        
        nameLabel.snp.makeConstraints { make in
            make.top.equalTo(avatarImageView.snp.bottom).offset(16)
            make.centerX.equalToSuperview()
        }
        
        bioLabel.snp.makeConstraints { make in
            make.top.equalTo(nameLabel.snp.bottom).offset(16)
            make.left.right.equalToSuperview().inset(32)
        }
        
        statsStack.snp.makeConstraints { make in
            make.top.equalTo(bioLabel.snp.bottom).offset(32)
            make.centerX.equalToSuperview()
        }
        
        editButton.snp.makeConstraints { make in
            make.top.equalTo(statsStack.snp.bottom).offset(32)
            make.left.right.equalToSuperview().inset(32)
            make.height.equalTo(50)
            make.bottom.equalToSuperview().offset(-40) // ContentView o'lchami shu yergacha!
        }
    }
}
```

---

## 16. KATTA AMALIY LOYIHA 2: Product Card {#loyiha2}

Ushbu misolda shadow va corner radiuslar qanday qilib kompleks tarzda ishlashini ko'ramiz.

### SwiftUI'da:
```swift
struct ProductCard: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Color.gray // Rasm o'rni (4:3)
                .aspectRatio(4/3, contentMode: .fit)
                
            Text("AirPods Pro")
                .font(.headline)
                .padding(.horizontal, 12)
                
            HStack {
                Text("$249.00").bold()
                Spacer()
                Text("⭐️ 4.8")
            }
            .padding(.horizontal, 12)
            
            Button("Add to Cart") {}
                .padding()
                .frame(maxWidth: .infinity)
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(8)
                .padding(12)
        }
        .background(Color.white)
        .cornerRadius(12)
        .shadow(color: .black.opacity(0.1), radius: 10, y: 5)
        .padding()
    }
}
```

### Endi xuddi shu layout'ni SnapKit yordamida qilamiz:
```swift
import UIKit
import SnapKit

class ProductCardView: UIView {
    
    let productImageView = UIImageView()
    let titleLabel = UILabel()
    let priceLabel = UILabel()
    let ratingLabel = UILabel()
    let addButton = UIButton(type: .system)
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupStyle()
        setupViews()
        setupConstraints()
    }
    
    required init?(coder: NSCoder) { fatalError() }
    
    private func setupStyle() {
        backgroundColor = .white
        layer.cornerRadius = 12
        
        // Shadow configuration
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOpacity = 0.1
        layer.shadowRadius = 10
        layer.shadowOffset = CGSize(width: 0, height: 5)
        clipsToBounds = false
        
        productImageView.backgroundColor = .systemGray5
        productImageView.layer.cornerRadius = 12
        productImageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
        productImageView.clipsToBounds = true
        
        titleLabel.text = "AirPods Pro"
        titleLabel.font = .systemFont(ofSize: 17, weight: .semibold)
        
        priceLabel.text = "$249.00"
        priceLabel.font = .boldSystemFont(ofSize: 16)
        
        ratingLabel.text = "⭐️ 4.8"
        ratingLabel.font = .systemFont(ofSize: 14)
        
        addButton.setTitle("Add to Cart", for: .normal)
        addButton.backgroundColor = .systemBlue
        addButton.setTitleColor(.white, for: .normal)
        addButton.layer.cornerRadius = 8
    }
    
    private func setupViews() {
        addSubview(productImageView)
        addSubview(titleLabel)
        addSubview(priceLabel)
        addSubview(ratingLabel)
        addSubview(addButton)
    }
    
    private func setupConstraints() {
        productImageView.snp.makeConstraints { make in
            make.top.left.right.equalToSuperview()
            // Aspect ratio 4:3 -> height = width * 0.75
            make.height.equalTo(productImageView.snp.width).multipliedBy(0.75)
        }
        
        titleLabel.snp.makeConstraints { make in
            make.top.equalTo(productImageView.snp.bottom).offset(12)
            make.left.right.equalToSuperview().inset(12)
        }
        
        priceLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(8)
            make.left.equalToSuperview().inset(12)
        }
        
        ratingLabel.snp.makeConstraints { make in
            make.centerY.equalTo(priceLabel)
            make.right.equalToSuperview().inset(12)
            make.left.greaterThanOrEqualTo(priceLabel.snp.right).offset(8)
        }
        
        addButton.snp.makeConstraints { make in
            make.top.equalTo(priceLabel.snp.bottom).offset(16)
            make.left.right.bottom.equalToSuperview().inset(12)
            make.height.equalTo(44)
        }
    }
}
```

---

## 17. SwiftUI vs SnapKit: Qachon qaysi biri? {#qachon}

Ikkala yondashuvning ham o'z kuchli va zaif tomonlari bor. Quyidagi jadval qachon qaysi birini tanlash haqida:

| Mezon | SwiftUI | SnapKit (UIKit) | Izoh |
|-------|---------|-----------------|------|
| **Tezlik** | ✅ Juda tez | ⚠️ O'rtacha | SwiftUI yordamida UI ni tezroq terish mumkin, chunki u deklarativ. |
| **Kontrol** | ⚠️ Kamroq | ✅ To'liq | SnapKit (UIKit) da har bir pixel, constraint'lar va view ierarxiyasi ustidan to'liq nazorat bor. |
| **Performance** | ⚠️ O'rtacha | ✅ Yuqori | UIKit framework'i past darajali bo'lgani uchun, ayniqsa ro'yxatlar va murakkab layoutlarda barqarorroq ishlashi mumkin. |
| **Animatsiya** | ✅ Oson | ✅ Murakkab | SwiftUI da oddiy animatsiyalar juda oson, ammo murakkab va interaktiv animatsiyalar uchun UIKit qulay. |
| **Versiya (Legacy)** | ❌ iOS 13+ (Asosan 15+) | ✅ iOS 12+ (Eski versiyalar) | Eski proyektlar (Legacy code) asosan UIKit da. SnapKit esa uning eng yaxshi yordamchisi. |
| **Ishga Joylashish** | ⚠️ Yaxshi | ✅ Yuqori Talab | Ko'pgina katta va mavjud proyektlar hamon UIKit/SnapKit ga asoslangan. Ikkalasini ham bilish katta ustunlik. |

---

## Xulosa {#xulosa}

Agar siz SwiftUI ni bilsangiz, UIKit da UI qanday qurilishini tasavvur qilish ancha osonlashadi. SnapKit bu - UIKit constraint'larini SwiftUI singari intuitiv qilib beruvchi vositadir. SwiftUI'dagi `VStack`, `HStack` lar UIKit'da `UIStackView` va `SnapKit` ning moslashuvchan funksiyalari orqali xuddi shunday amalga oshiriladi. Eng asosiysi - ikkala freymvork ortidagi "layout mantiqi" (masofa, joylashuv, o'lchamlar) deyarli bir xil, faqat sintaksis farq qiladi xolos.

## Manbalar {#manbalar}
- [SnapKit Rasmiy Dokumentatsiyasi](http://snapkit.io/docs/)
- [Apple Developer: Auto Layout Guide](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html)
- [SwiftUI Rasmiy Dokumentatsiyasi](https://developer.apple.com/xcode/swiftui/)
