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
- UIStackView nima va nima uchun kerak?
- SnapKit bilan UIStackView joylash
- Nested StackView'lar (Ichma-ich)
- Dinamik StackView
- Custom Spacing (iOS 11+)
- Amaliy loyiha 1: Settings ekrani
- Amaliy loyiha 2: Tag Cloud / Chip Layout
- StackView vs Manual Constraints qachon qaysi biri?
- Xulosa
- 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:
- StackView'ning o'zini ekranga (superview'ga) SnapKit orqali yopishtirasiz.
- Ichidagi (
arrangedSubviews) elementlarga alohida position (x, y) constraintlari BERMANG — buni stack boshqaradi! - LEKIN
arrangedSubviews'larning o'lchamlarini (width, height) SnapKit orqali bersangiz bo'ladi.
Senior eslatmasi: StackView ichidagi elementga
.top,.leftkabi constraint bermang. Faqatgina.widthyoki.heightbersangiz 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
UICollectionViewDelegateFlowLayoutda label'ning intrinsic size'iga qarab berasiz.*
8. StackView vs Manual Constraints qachon qaysi biri? {#taqqoslash}
| Xususiyat | UIStackView + SnapKit | Faqat SnapKit (Manual Constraints) |
|---|---|---|
| Qo'llanilishi | Yonma-yon, ketma-ket, formalar, ro'yxatlar | Bir-birining ustiga chiqadigan (overlapping), erkin joylashuv |
| Moslashuvchanlik | Elementlar osongina yashiriladi va animatsiya qilinadi | Har bir constraint'ni manual update yoki deactivate qilish kerak |
| Tezlik (Dev) | Juda tez va o'qish oson | Ko'p chiziq kod, murakkablik yuqori bo'lishi mumkin |
| Performance | Bir nechta ichma-ich stack'lar CPU uchun ozgina og'irroq | To'g'ridan-to'g'ri bog'lanish tufayli bir oz samaraliroq |
Muhim: Har doim oddiy layoutlar uchun
UIStackViewdan boshlang. Qachonki StackView siz xohlagan dizaynni chiqara olmasa, undan keyingina sof SnapKit constraintlariga o'ting.
Xulosa {#xulosa}
UIStackViewvaSnapKit— 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.
isHiddenorqali elementlarni yashirish StackView'da mukammal ishlaydi va avtomatik qisqaradi.- StackView bilan "qotib qolgan" (rigid) layoutlardan qochamiz va barcha ekran o'lchamlariga mos dizayn yaratamiz.