Azimjon Abdurasulov

SnapKit 10: UIStackView + SnapKit Kombinatsiyasi — Tez, Oson va Moslashuvchan Layoutlar

🧩 SnapKit — Zero to Hero

SnapKit 10: UIStackView + SnapKit Kombinatsiyasi — Tez, Oson va Moslashuvchan Layoutlar

Holat: Ushbu darslik 2026-yil oktabr oyi holatiga ko'ra eng so'nggi iOS va SnapKit amaliyotlari asosida tayyorlangan.

Mundarija

  1. UIStackView nima va nima uchun kerak?
  2. SnapKit bilan UIStackView joylash
  3. Nested StackView'lar (Ichma-ich)
  4. Dinamik StackView
  5. Custom Spacing (iOS 11+)
  6. Amaliy loyiha 1: Settings ekrani
  7. Amaliy loyiha 2: Tag Cloud / Chip Layout
  8. StackView vs Manual Constraints qachon qaysi biri?
  9. Xulosa
  10. Manbalar

1. UIStackView nima va nima uchun kerak? {#stackview-nima}

UIStackView — bir qancha view'larni gorizontal yoki vertikal qatorda avtomatik tartibga soluvchi kuchli konteyner view hisoblanadi. Unda har bir ichki element (arrangedSubview) uchun alohida constraint yozish shart emas; StackView ularni quyidagi xususiyatlar (properties) asosida o'zi boshqaradi:

  • axis: .horizontal (yonma-yon) yoki .vertical (ketma-ket, yuqoridan pastga).
  • distribution: Elementlar o'q bo'ylab qanday yoyilishini belgilaydi (.fill, .fillEqually, .fillProportionally, .equalSpacing, .equalCentering).
  • alignment: Elementlar o'qqa nisbatan perpendikulyar joylashishini belgilaydi (.fill, .center, .leading, .trailing, .top, .bottom).
  • spacing: Elementlar orasidagi bo'shliq miqdori (points).
+-------------------+
| UIStackView       |
|  [ View 1 ]       |
|    | spacing      |
|  [ View 2 ]       |
|    | spacing      |
|  [ View 3 ]       |
+-------------------+

2. SnapKit bilan UIStackView joylash {#snapkit-bilan-joylash}

StackView ham xuddi oddiy UIView kabi superview'ga joylanadi va SnapKit aynan shu yerda juda qulay:

  1. StackView'ning o'zini ekranga (superview'ga) SnapKit orqali yopishtirasiz.
  2. Ichidagi (arrangedSubviews) elementlarga alohida position (x, y) constraintlari BERMANG — buni stack boshqaradi!
  3. LEKIN arrangedSubviews'larning o'lchamlarini (width, height) SnapKit orqali bersangiz bo'ladi.

Senior eslatmasi: StackView ichidagi elementga .top, .left kabi constraint bermang. Faqatgina .width yoki .height bersangiz bo'ladi.

import UIKit
import SnapKit

class StackViewExampleVC: UIViewController {
    
    private let stackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 16
        stack.alignment = .fill
        stack.distribution = .fill
        return stack
    }()
    
    private let button1: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Tugma 1", for: .normal)
        btn.backgroundColor = .systemBlue
        return btn
    }()
    
    private let button2: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Tugma 2", for: .normal)
        btn.backgroundColor = .systemGreen
        return btn
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupSubviews()
        setupConstraints()
    }
    
    private func setupSubviews() {
        view.backgroundColor = .white
        view.addSubview(stackView)
        
        stackView.addArrangedSubview(button1)
        stackView.addArrangedSubview(button2)
    }
    
    private func setupConstraints() {
        // 1. StackView'ning o'zini joylashtiramiz
        stackView.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.leading.trailing.equalToSuperview().inset(20)
        }
        
        // 2. Elementlarning faqatgina balandligini (height) belgilaymiz
        button1.snp.makeConstraints { make in
            make.height.equalTo(50)
        }
        
        button2.snp.makeConstraints { make in
            make.height.equalTo(50)
            // Yoki stackview'ga nisbatan kenglikni proporsional berish mumkin:
            // make.width.equalTo(stackView).multipliedBy(0.5) 
        }
    }
}

3. Nested StackView'lar (Ichma-ich) {#nested-stackview}

Murakkab layoutlarni yaratishda bitta StackView yetarli bo'lmaydi. Biz bitta katta vertikal stack ichiga kichkina gorizontal stacklarni joylashimiz mumkin. Masalan, Forma yoki Profil ekrani.

[ Vertical StackView ]
  |-- [ Horizontal StackView: Icon | Label | Switch ]
  |-- [ Horizontal StackView: Icon | Label | Textfield ]
import UIKit
import SnapKit

class ProfileRowView: UIView {
    
    private let horizontalStack: UIStackView = {
        let stack = UIStackView()
        stack.axis = .horizontal
        stack.spacing = 12
        stack.alignment = .center
        return stack
    }()
    
    private let iconImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .lightGray
        iv.layer.cornerRadius = 8
        return iv
    }()
    
    private let titleLabel: UILabel = {
        let lbl = UILabel()
        lbl.font = .systemFont(ofSize: 16, weight: .medium)
        return lbl
    }()
    
    private let toggleSwitch = UISwitch()
    
    init(title: String) {
        super.init(frame: .zero)
        titleLabel.text = title
        setupSubviews()
        setupConstraints()
    }
    
    required init?(coder: NSCoder) { fatalError() }
    
    private func setupSubviews() {
        addSubview(horizontalStack)
        horizontalStack.addArrangedSubview(iconImageView)
        horizontalStack.addArrangedSubview(titleLabel)
        horizontalStack.addArrangedSubview(toggleSwitch)
    }
    
    private func setupConstraints() {
        horizontalStack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(16)
        }
        
        iconImageView.snp.makeConstraints { make in
            make.size.equalTo(30)
        }
        
        // titleLabel va toggleSwitch o'lchamlari avtomatik aniqlanadi (intrinsic content size)
    }
}

4. Dinamik StackView {#dinamik-stackview}

UIStackView ning eng kuchli tomonlaridan biri — runtime davomida (dastur ishlash jarayonida) elementlarni qo'shish, olib tashlash va yashirish (isHidden). Siz elementni yashirganingizda (isHidden = true), StackView qolgan elementlarni avtomatik ravishda qayta joylashtiradi (collapse qiladi).

Animatsiya bilan yashirish:

UIView.animate(withDuration: 0.3) {
    // 3-elementni yashiramiz
    self.stackView.arrangedSubviews[2].isHidden = true
    self.view.layoutIfNeeded()
}

Dinamik qo'shish va olib tashlash:

// Oxiriga qo'shish
stackView.addArrangedSubview(newView)

// Aniq indeksga qo'shish
stackView.insertArrangedSubview(newView, at: 1)

// Olib tashlash (Ikkala qadam ham muhim!)
stackView.removeArrangedSubview(oldView)
oldView.removeFromSuperview()

5. Custom Spacing (iOS 11+) {#custom-spacing}

Odatda stackView.spacing barcha elementlar o'rtasida bir xil bo'shliq qoldiradi. Agar qaysidir elementdan keyin ko'proq joy tashlash kerak bo'lsa, setCustomSpacing(_:after:) metodi ishlatiladi:

let titleLabel = UILabel()
let subtitleLabel = UILabel()
let contentText = UILabel()

stackView.addArrangedSubview(titleLabel)
stackView.addArrangedSubview(subtitleLabel)
stackView.addArrangedSubview(contentText)

// Title va subtitle orasida default spacing ishlaydi
// Lekin subtitle va contentText orasida 24 point joy qoldiramiz:
stackView.setCustomSpacing(24, after: subtitleLabel)

6. Amaliy loyiha 1: Settings ekrani {#loyiha-settings}

Endi o'rganganlarimizni birlashtirib, oddiy Sozlamalar (Settings) ekranini yaratamiz. Biz buni ScrollView > Vertical StackView > Custom Row View uslubida qilamiz.

import UIKit
import SnapKit

class SettingsViewController: UIViewController {
    
    private let scrollView = UIScrollView()
    
    private let mainStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 0 // Elementlar orasida chiziq (separator) chizamiz
        return stack
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Sozlamalar"
        setupSubviews()
        setupConstraints()
        populateSettings()
    }
    
    private func setupSubviews() {
        view.backgroundColor = .systemBackground
        view.addSubview(scrollView)
        scrollView.addSubview(mainStackView)
    }
    
    private func setupConstraints() {
        scrollView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        mainStackView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalTo(scrollView) // Vertical scroll uchun kenglik fix qilinishi kerak
        }
    }
    
    private func populateSettings() {
        let settings = ["Profil", "Xavfsizlik", "Bildirishnomalar", "Tizim haqida"]
        
        for (index, title) in settings.enumerated() {
            let row = SettingsRowView(title: title)
            mainStackView.addArrangedSubview(row)
            
            // Oxirgi elementdan tashqari hammasiga chiziq qo'shamiz
            if index < settings.count - 1 {
                let separator = UIView()
                separator.backgroundColor = .separator
                mainStackView.addArrangedSubview(separator)
                
                separator.snp.makeConstraints { make in
                    make.height.equalTo(0.5)
                }
            }
        }
    }
}

// Row component
class SettingsRowView: UIView {
    private let titleLabel = UILabel()
    private let chevronIcon = UIImageView(image: UIImage(systemName: "chevron.right"))
    
    init(title: String) {
        super.init(frame: .zero)
        titleLabel.text = title
        chevronIcon.tintColor = .tertiaryLabel
        
        let stack = UIStackView(arrangedSubviews: [titleLabel, chevronIcon])
        stack.axis = .horizontal
        stack.alignment = .center
        
        addSubview(stack)
        stack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))
        }
    }
    
    required init?(coder: NSCoder) { fatalError() }
}

7. Amaliy loyiha 2: Tag Cloud / Chip Layout {#loyiha-tag-cloud}

Agar sizda "Swift", "UIKit", "SnapKit" kabi turli uzunlikdagi tag'lar bo'lsa va ular ekranga sig'magan joyda keyingi qatorga tushishi kerak bo'lsa, UIStackView bunga mos kelmaydi. StackView faqat bir qatorda yoki bir ustunda joylashtira oladi (wrapping yo'q).

Bunday layout (Tag Cloud) uchun UICollectionView (FlowLayout bilan) yoki maxsus o'rab oluvchi (wrapping) logic ishlatish kerak. SnapKit esa cell ichidagi elementlarni joylash uchun xizmat qiladi:

import UIKit
import SnapKit

class TagCell: UICollectionViewCell {
    let titleLabel = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        contentView.backgroundColor = .systemBlue.withAlphaComponent(0.1)
        contentView.layer.cornerRadius = 12
        titleLabel.textColor = .systemBlue
        
        contentView.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 8, left: 12, bottom: 8, right: 12))
        }
    }
    
    required init?(coder: NSCoder) { fatalError() }
}

*Cell o'lchamini UICollectionViewDelegateFlowLayout da label'ning intrinsic size'iga qarab berasiz.*

8. StackView vs Manual Constraints qachon qaysi biri? {#taqqoslash}

XususiyatUIStackView + SnapKitFaqat SnapKit (Manual Constraints)
Qo'llanilishiYonma-yon, ketma-ket, formalar, ro'yxatlarBir-birining ustiga chiqadigan (overlapping), erkin joylashuv
MoslashuvchanlikElementlar osongina yashiriladi va animatsiya qilinadiHar bir constraint'ni manual update yoki deactivate qilish kerak
Tezlik (Dev)Juda tez va o'qish osonKo'p chiziq kod, murakkablik yuqori bo'lishi mumkin
PerformanceBir nechta ichma-ich stack'lar CPU uchun ozgina og'irroqTo'g'ridan-to'g'ri bog'lanish tufayli bir oz samaraliroq

Muhim: Har doim oddiy layoutlar uchun UIStackView dan boshlang. Qachonki StackView siz xohlagan dizaynni chiqara olmasa, undan keyingina sof SnapKit constraintlariga o'ting.

Xulosa {#xulosa}

  • UIStackView va SnapKit — iOS dasturlashdagi eng kuchli juftlik.
  • StackView elementlarni taqsimlaydi, SnapKit esa ularning aniq o'lchamlarini (width/height) yoki stack'ning o'zining superview'dagi o'rnini belgilaydi.
  • isHidden orqali elementlarni yashirish StackView'da mukammal ishlaydi va avtomatik qisqaradi.
  • StackView bilan "qotib qolgan" (rigid) layoutlardan qochamiz va barcha ekran o'lchamlariga mos dizayn yaratamiz.

Manbalar {#manbalar}

Markdown manba

iOS Lessons