SnapKit 3: View'lar Orasidagi Munosabatlar — Spacing, Chaining va ConstraintMaker sirlari
🧩 SnapKit — Zero to Hero
SnapKit 3: View'lar Orasidagi Munosabatlar — Spacing, Chaining va ConstraintMaker sirlari
Holat: 2026-yil oktabr holatiga ko'ra, murakkab UI qismlarini yaratishda UIStackView o'rniga ba'zan SnapKit yordamida view'larni bevosita bir-biriga ulash (view-to-view constraints) moslashuvchanlik nuqtai nazaridan afzalroq bo'ladi.
Mundarija
- View-to-View Constraints
- Constraint Chaining (Zanjir)
- ConstraintMaker Ichki Arxitekturasi
- ConstraintItem vs ConstraintView
- Spacing Pattern'lari
- Amaliy Loyiha: Profil Kartasi
- Amaliy Loyiha 2: Settings Row
- Xulosa
- Manbalar
1. View-to-View Constraints {#view-to-view}
View'larni har doim ham superview'ga bog'lash shart emas. Ko'pincha biz ularni bir-biriga nisbatan joylashtiramiz. Bu UIStackView'ning ishlashiga o'xshaydi, lekin to'liq nazorat sizda bo'ladi.
import UIKit
import SnapKit
class RelationView: UIView {
let avatarView = UIView()
let titleLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupSubviews() {
avatarView.backgroundColor = .blue
titleLabel.text = "Azimjon"
titleLabel.backgroundColor = .yellow
addSubview(avatarView)
addSubview(titleLabel)
}
private func setupConstraints() {
avatarView.snp.makeConstraints { make in
make.top.leading.equalToSuperview().inset(16)
make.size.equalTo(CGSize(width: 50, height: 50))
}
titleLabel.snp.makeConstraints { make in
// titleLabel'ning chap tomoni avatarView'ning o'ng tomonidan 12 pt uzoqda
make.leading.equalTo(avatarView.snp.trailing).offset(12)
// titleLabel'ning markazi avatarView'ning markaziga teng (gorizontaliga bir xil balandlikda)
make.centerY.equalTo(avatarView.snp.centerY)
// O'ng tomoni superview chetidan chiqib ketmasligi uchun
make.trailing.lessThanOrEqualToSuperview().inset(16)
}
}
}
Senior eslatmasi: Agar bir view ikkinchisiga
equalToqilinsa, har ikkalasi ham bir xil parent view ierarxiyasida (masalan, bitta superview ichida yoki biri ikkinchisining siblingi) bo'lishi kerak.
2. Constraint Chaining (Zanjir) {#chaining}
SnapKit kodni qisqartirish imkonini beradi. Bitta satrda bir nechta anchor'larni "zanjir" qilib yozish mumkin.
import UIKit
import SnapKit
class ChainingExampleView: UIView {
let boxView = UIView()
let innerBox = UIView()
private func setupConstraints() {
addSubview(boxView)
boxView.addSubview(innerBox)
boxView.snp.makeConstraints { make in
// 4 ta qator o'rniga 1 ta qator!
make.top.bottom.leading.trailing.equalToSuperview().inset(20)
// Bu bilan bir xil:
// make.edges.equalToSuperview().inset(20)
}
innerBox.snp.makeConstraints { make in
// Zanjir faqat bir xil o'lchov o'qlari bo'yicha ishlashi eng xavfsizidir
make.top.leading.equalToSuperview().inset(10)
make.width.height.equalTo(100) // Kenglik va balandlikni bittada berish
}
}
}
Qachon chain qilish mumkin?
- Barcha zanjirlangan anchor'lar bitta narsaga (
equalTo) tenglashayotgan bo'lsa. - Ular barchasi bitta
offsetyokiinsetqabul qilsa.
3. ConstraintMaker Ichki Arxitekturasi {#constraintmaker}
SnapKit orqasida nima sodir bo'ladi?
makeo'zgaruvchisi aslidaConstraintMakerturidagi obyektdir.- Siz
make.topdeb yozganingizda, uConstraintMakerRelatableobyekti qaytaradi. .equalTo(...)chaqirilganda, u orqadaConstraintDescriptionhosil qiladi va xotirada saqlaydi.- Closure tugashi bilan, SnapKit yig'ilgan barcha
ConstraintDescription'larni olib, xaqiqiyNSLayoutConstraint'larni yaratadi va barchasini birdaniga aktivlashtiradi (batch activation).
Muhim: Bu arxitektura "Builder Pattern" ga misoldir. Closure ichida bevosita constraintlar yasalmaydi, faqatgina qoidalar yig'iladi, closure tugagach esa ular amalda qo'llaniladi.
4. ConstraintItem vs ConstraintView {#item-vs-view}
Ba'zida aniq anchor ko'rsatamiz, ba'zida faqat view'ning o'zini yozamiz.
// ConstraintView - view'ning o'zini berish
make.top.equalTo(otherView)
Bu holda SnapKit aqlli harakat qiladi va siz qaysi anchor'dan (chap tomonda) kelayotganingizga qarab, o'ng tomondagi view'ning o'sha anchor'ini tanlaydi. Yuqoridagi kod aslida: make.top.equalTo(otherView.snp.top) bilan bir xil.
// ConstraintItem - aniq anchor'ni ko'rsatish
make.top.equalTo(otherView.snp.bottom).offset(10)
Bu yerda .top ni .bottom ga ulayapmiz. Shu sababli aniq otherView.snp.bottom deb yozish shart. Aks holda SnapKit top'ni top'ga ulab qo'yadi.
5. Spacing Pattern'lari {#spacing}
View'larni bir-biriga nisbatan joylashtirishning asosiy pattern'lari.
[ Vertikal Stack Pattern ]
+------------------+
| View 1 |
+------------------+
| offset(16)
+------------------+
| View 2 |
+------------------+
view1.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview().inset(16)
make.height.equalTo(100)
}
view2.snp.makeConstraints { make in
make.top.equalTo(view1.snp.bottom).offset(16)
make.leading.trailing.equalToSuperview().inset(16)
make.height.equalTo(100)
}
Teng bo'shliqlar saqlash (Equal Spacing) uchun ko'pincha UILayoutGuide ishlatiladi, ammo SnapKit'da buni oddiygina "spacer view"lar bilan yoki faqat matematika yordamida qilsa ham bo'ladi: make.width.equalTo(superview).multipliedBy(0.5).offset(-20) (yarmi minus padding).
6. Amaliy Loyiha: Profil Kartasi {#amaliy-1}
Avatar chapda, o'ngroqda ustma-ust 2 ta yozuv va eng o'ng chekkada ikonka.
import UIKit
import SnapKit
class ProfileCardView: UIView {
let avatarImageView = UIImageView()
let titleLabel = UILabel()
let subtitleLabel = UILabel()
let chevronImageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
setupConstraints()
}
required init?(coder: NSCoder) { fatalError() }
private func setupSubviews() {
backgroundColor = .systemBackground
layer.cornerRadius = 12
avatarImageView.backgroundColor = .systemGray
avatarImageView.layer.cornerRadius = 25
avatarImageView.clipsToBounds = true
titleLabel.font = .boldSystemFont(ofSize: 16)
titleLabel.text = "Azimjon"
subtitleLabel.font = .systemFont(ofSize: 14)
subtitleLabel.textColor = .secondaryLabel
subtitleLabel.text = "iOS Developer"
chevronImageView.image = UIImage(systemName: "chevron.right")
chevronImageView.tintColor = .systemGray
addSubview(avatarImageView)
addSubview(titleLabel)
addSubview(subtitleLabel)
addSubview(chevronImageView)
}
private func setupConstraints() {
avatarImageView.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(16)
make.centerY.equalToSuperview()
make.size.equalTo(50)
make.top.bottom.equalToSuperview().inset(16).priority(.high)
}
titleLabel.snp.makeConstraints { make in
make.leading.equalTo(avatarImageView.snp.trailing).offset(12)
make.bottom.equalTo(avatarImageView.snp.centerY).offset(-2)
make.trailing.lessThanOrEqualTo(chevronImageView.snp.leading).offset(-8)
}
subtitleLabel.snp.makeConstraints { make in
make.leading.equalTo(titleLabel) // titleLabel bilan bir xil alignment
make.top.equalTo(avatarImageView.snp.centerY).offset(2)
make.trailing.lessThanOrEqualTo(chevronImageView.snp.leading).offset(-8)
}
chevronImageView.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-16)
make.centerY.equalToSuperview()
make.size.equalTo(20)
}
}
}
7. Amaliy Loyiha 2: Settings Row {#amaliy-2}
Sozlamalar qatori — iconka, yozuv, qoshimcha yozuv (o'ngroqda) va Switch.
import UIKit
import SnapKit
class SettingsRowView: UIView {
let iconView = UIImageView()
let titleLabel = UILabel()
let detailLabel = UILabel()
let toggleSwitch = UISwitch()
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
setupConstraints()
}
required init?(coder: NSCoder) { fatalError() }
private func setupSubviews() {
iconView.backgroundColor = .systemBlue
iconView.layer.cornerRadius = 8
titleLabel.text = "Notifications"
detailLabel.text = "On"
detailLabel.textColor = .secondaryLabel
addSubview(iconView)
addSubview(titleLabel)
addSubview(detailLabel)
addSubview(toggleSwitch)
}
private func setupConstraints() {
iconView.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(16)
make.centerY.equalToSuperview()
make.size.equalTo(30)
make.top.bottom.equalToSuperview().inset(12)
}
titleLabel.snp.makeConstraints { make in
make.leading.equalTo(iconView.snp.trailing).offset(16)
make.centerY.equalToSuperview()
}
toggleSwitch.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-16)
make.centerY.equalToSuperview()
}
detailLabel.snp.makeConstraints { make in
make.trailing.equalTo(toggleSwitch.snp.leading).offset(-12)
make.centerY.equalToSuperview()
// Detail label juda uzun bo'lib ketsa, titleLabel ni siqib qo'ymasligi uchun:
make.leading.greaterThanOrEqualTo(titleLabel.snp.trailing).offset(16)
}
}
}
Xulosa {#xulosa}
SnapKit'ning eng kuchli tomoni bu view'larni bir-biriga bog'lashdagi sintaksisning soddaligidadir. equalTo, offset, inset kabi metodlar va zanjir(chain) yozish uslubi orqali murakkab interfeyslarni UIStackView'siz ham tez qurish mumkin. Bunda albatta SnapKit'ning tagidagi ConstraintMaker va Builder pattern arxitekturasi katta rol o'ynaydi.
Manbalar {#manbalar}
- SnapKit Rasmiy Dokumentatsiyasi - Spacing
- "iOS Auto Layout Demystified" by Erica Sadun
- Apple Auto Layout Guide - Constraints