Azimjon Abdurasulov

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

🧩 SnapKit — Zero to Hero

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
  2. HStack → Gorizontal Layout
  3. ZStack → Ustma-ust qo'yish (Layering)
  4. .padding() → inset/offset
  5. .frame(width:height:) → size constraints
  6. .background() / .overlay() → background va overlay view
  7. Spacer() → Bo'sh joy
  8. .cornerRadius / .clipShape → layer.cornerRadius
  9. .shadow → layer.shadow
  10. ScrollView → UIScrollView
  11. List → UITableView
  12. @State / Animation → Constraint Animation
  13. GeometryReader → layoutSubviews / bounds
  14. NavigationStack → UINavigationController
  15. KATTA AMALIY LOYIHA 1: Profil ekrani
  16. KATTA AMALIY LOYIHA 2: Product Card
  17. SwiftUI vs SnapKit: Qachon qaysi biri?
  18. Xulosa
  19. 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:

VStack(spacing: 16) {
    Text("Salom")
    Button("Bosing") {}
}

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

1-usul: UIStackView (Tavsiya etiladi)

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)

// 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:

HStack(spacing: 12) {
    Image(systemName: "star")
    Text("Reyting")
    Spacer()
    Button("Ko'rish") {}
}

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

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

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

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:

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:

Color.red
    .frame(width: 200, height: 100)
    .frame(maxWidth: .infinity)
    .frame(minHeight: 44)
    .frame(maxWidth: 300)

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

Text("Salom")
    .background(Color.blue)
    
Text("Salom")
    .background(RoundedRectangle(cornerRadius: 8).fill(.blue))

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

HStack {
    Text("Chapda")
    Spacer()
    Text("O'ngda")
}

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

a) UIView() spacer (Eng oson, UIStackView bilan):

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.

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):

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:

Image("profile")
    .cornerRadius(12)
    
Image("profile")
    .clipShape(Circle())

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

Color.white
    .shadow(color: .black.opacity(0.2), radius: 8, x: 0, y: 4)

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

ScrollView {
    VStack {
        Text("Tepa")
        // ... ko'p elementlar
        Text("Past")
    }
}

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

List {
    ForEach(items) { item in
        Text(item.name)
    }
}

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

// 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:

@State var isExpanded = false

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

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

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:

GeometryReader { geo in
    Color.red
        .frame(width: geo.size.width * 0.5) // Ekranning yarmi
}

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

// 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:

NavigationStack {
    VStack { ... }
    .navigationTitle("Asosiy")
}

Endi xuddi shu layout'ni SnapKit yordamida qilamiz:

// 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):

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):

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:

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:

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:

MezonSwiftUISnapKit (UIKit)Izoh
Tezlik✅ Juda tez⚠️ O'rtachaSwiftUI yordamida UI ni tezroq terish mumkin, chunki u deklarativ.
Kontrol⚠️ Kamroq✅ To'liqSnapKit (UIKit) da har bir pixel, constraint'lar va view ierarxiyasi ustidan to'liq nazorat bor.
Performance⚠️ O'rtacha✅ YuqoriUIKit framework'i past darajali bo'lgani uchun, ayniqsa ro'yxatlar va murakkab layoutlarda barqarorroq ishlashi mumkin.
Animatsiya✅ Oson✅ MurakkabSwiftUI 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 TalabKo'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}

Markdown manba

iOS Lessons