SnapKit 4: Tengsizliklar va Nisbatlar — greaterThanOrEqualTo, lessThanOrEqualTo, multipliedBy va Aspect Ratio
🧩 SnapKit — Zero to Hero
SnapKit 4: Tengsizliklar va Nisbatlar — greaterThanOrEqualTo, lessThanOrEqualTo, multipliedBy va Aspect Ratio
Holat: 2026-yil oktabr holatiga ko'ra, SnapKit orqali moslashuvchan (responsive) va barcha ekran o'lchamlariga mos keladigan interfeyslar yaratish uchun tengsizliklar va nisbatlar (ratios) eng ko'p ishlatiladigan vositalardir. Dynamic Type va turli ekranlar (iPhone SE dan iPad Pro gacha) davrida moslashuvchanlik qat'iy o'lchamlardan muhimroq.
Mundarija
- Tengsizlik Constraint'lar (Inequality)
- multipliedBy va dividedBy
- Aspect Ratio (Tomonlar nisbati)
- Minimum va Maximum o'lcham strategiyasi
- Amaliy loyiha: Responsive Card Layout
- Amaliy loyiha 2: Image Gallery Grid
- Xulosa
- Manbalar
1. Tengsizlik Constraint'lar (Inequality) {#inequality}
Odatda biz equalTo orqali view'ning o'lchami yoki joylashuvini qat'iy belgilaymiz. Lekin ba'zida "kamida shuncha bo'lsin" yoki "bundan oshib ketmasin" degan shartlar kerak bo'ladi. SnapKit buning uchun greaterThanOrEqualTo (>=) va lessThanOrEqualTo (<=) metodlarini taqdim etadi.
+-----------------------+
| SuperView |
| |
| [ View (Min 44pt) ] | <-- Balandligi kamida 44pt, lekin kontent ko'paysa o'sishi mumkin
| |
+-----------------------+
Kod misoli
import UIKit
import SnapKit
class InequalityViewController: UIViewController {
private let actionButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Davom etish", for: .normal)
button.backgroundColor = .systemBlue
button.setTitleColor(.white, for: .normal)
button.layer.cornerRadius = 8
return button
}()
private let descriptionLabel: UILabel = {
let label = UILabel()
label.text = "Bu juda uzun matn bo'lishi mumkin. Kichik ekranlarda ko'p joy egallaydi."
label.numberOfLines = 0
label.backgroundColor = .systemGray5
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupSubviews()
setupConstraints()
}
private func setupSubviews() {
view.addSubview(actionButton)
view.addSubview(descriptionLabel)
}
private func setupConstraints() {
// Button uchun Apple HIG qoidasi: tap area kamida 44x44 pt bo'lishi kerak
actionButton.snp.makeConstraints { make in
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-20)
make.centerX.equalToSuperview()
// Kengligi ekran kengligidan biroz kichik bo'lsin, lekin maksimal 300 pt
make.width.equalToSuperview().offset(-40)
make.width.lessThanOrEqualTo(300)
// Balandligi kamida 44pt
make.height.greaterThanOrEqualTo(44)
}
descriptionLabel.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide).offset(40)
make.leading.trailing.equalToSuperview().inset(20)
// Boshqa viewdan kam bo'lmasin
make.height.greaterThanOrEqualTo(actionButton)
}
}
}
Senior eslatmasi: Dynamic Type ishlatilganda matnlar kattalashishi sababli,
equalTo(44)kabi qat'iy balandlik berish xatodir. O'rniga doimgreaterThanOrEqualTo(44)ishlating.
2. multipliedBy va dividedBy {#multipliers}
Bitta view o'lchamini boshqa view o'lchamiga nisbatan foiz yoki ulush sifatida belgilash uchun multipliedBy va dividedBy ishlatiladi.
| Metod | Ma'nosi | Misol |
|---|---|---|
multipliedBy(x) | x ga ko'paytirish | .multipliedBy(0.5) (50%) |
dividedBy(x) | x ga bo'lish | .dividedBy(2) (50%) |
import UIKit
import SnapKit
class MultiplierViewController: UIViewController {
private let mainView: UIView = {
let view = UIView()
view.backgroundColor = .systemRed
return view
}()
private let subView: UIView = {
let view = UIView()
view.backgroundColor = .systemGreen
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupSubviews()
setupConstraints()
}
private func setupSubviews() {
view.addSubview(mainView)
view.addSubview(subView)
}
private func setupConstraints() {
mainView.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide).offset(20)
make.centerX.equalToSuperview()
// Eni superview enining 80% iga teng
make.width.equalToSuperview().multipliedBy(0.8)
make.height.equalTo(100)
}
subView.snp.makeConstraints { make in
make.top.equalTo(mainView.snp.bottom).offset(20)
make.centerX.equalToSuperview()
// subView kengligi mainView kengligining yarmiga teng (50%)
make.width.equalTo(mainView).dividedBy(2)
// XATO: make.height.equalTo(make.width).dividedBy(2) -> bunday yozish mumkin emas!
// TO'G'RI: o'zining width yoki boshqa view width iga nisbatan yozish
make.height.equalTo(subView.snp.width).multipliedBy(0.5) // Balandligi enining yarmi (2:1 nisbat)
}
}
}
3. Aspect Ratio (Tomonlar nisbati) {#aspect-ratio}
Rasmlar yoki videolar uchun ma'lum bir tomonlar nisbatini saqlab qolish juda muhim. Masalan, 16:9 (video) yoki 1:1 (kvadrat rasm). SnapKit'da Aspect Ratio ni multipliedBy yordamida view'ning o'z o'qi (snp.width va snp.height) orqali beramiz.
16:9 Video Aspect Ratio 1:1 Square
+-----------------------+ +--------+
| | | |
| | | |
| | +--------+
+-----------------------+ width = height
height = width * (9/16)
import UIKit
import SnapKit
class AspectRatioViewController: UIViewController {
private let videoPlayerView: UIView = {
let view = UIView()
view.backgroundColor = .black
return view
}()
private let avatarImageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .systemGray
iv.layer.cornerRadius = 50
iv.clipsToBounds = true
return iv
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupSubviews()
setupConstraints()
}
private func setupSubviews() {
view.addSubview(videoPlayerView)
view.addSubview(avatarImageView)
}
private func setupConstraints() {
videoPlayerView.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide).offset(20)
make.leading.trailing.equalToSuperview().inset(16)
// 16:9 aspect ratio
// height = width * 9 / 16
make.height.equalTo(videoPlayerView.snp.width).multipliedBy(9.0 / 16.0)
}
avatarImageView.snp.makeConstraints { make in
make.top.equalTo(videoPlayerView.snp.bottom).offset(30)
make.centerX.equalToSuperview()
make.width.equalTo(100)
// 1:1 Kvadrat aspect ratio (balandlik kenglikka teng)
make.height.equalTo(avatarImageView.snp.width)
}
}
}
4. Minimum va Maximum o'lcham strategiyasi {#min-max-strategy}
Responsive dizaynlarda ko'pincha "ideal o'lcham shuncha, lekin bunchadan oshmasin va undan kamaymasin" degan algoritm kerak bo'ladi. Buni prioritetlar va tengsizliklarni birlashtirish orqali hal qilamiz.
import UIKit
import SnapKit
class MinMaxViewController: UIViewController {
private let responsiveView: UIView = {
let view = UIView()
view.backgroundColor = .systemPurple
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupSubviews()
setupConstraints()
}
private func setupSubviews() {
view.addSubview(responsiveView)
}
private func setupConstraints() {
responsiveView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.height.equalTo(200)
// Kenglik superview'ning 80% bo'lishini xohlaymiz (Priority = High)
make.width.equalToSuperview().multipliedBy(0.8).priority(.high)
// Lekin 400 pt dan oshmasligi SHART (Priority = Required)
make.width.lessThanOrEqualTo(400).priority(.required)
// Va 200 pt dan kam bo'lmasligi SHART (Priority = Required)
make.width.greaterThanOrEqualTo(200).priority(.required)
}
}
}
Muhim:
.priority(.required)1000 ga teng bo'lib, xatoliksiz bajarilishi kerak. Agar qarama-qarshilik yuzaga kelsa, eng yuqori prioritetli qoida ishlaydi.
5. Amaliy loyiha: Responsive Card Layout {#project-card}
iPhone va iPad ekranlarida chiroyli ko'rinadigan maqola (Card) UI yaratsak.
import UIKit
import SnapKit
class ResponsiveCardViewController: UIViewController {
private let cardView: UIView = {
let view = UIView()
view.backgroundColor = .secondarySystemBackground
view.layer.cornerRadius = 16
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.1
view.layer.shadowOffset = CGSize(width: 0, height: 4)
view.layer.shadowRadius = 8
return view
}()
private let coverImageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .systemIndigo
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.layer.cornerRadius = 12
return iv
}()
private let titleLabel: UILabel = {
let label = UILabel()
label.text = "SnapKit orqali Responsive Layout yaratish usullari"
label.font = .systemFont(ofSize: 20, weight: .bold)
label.numberOfLines = 3 // Ko'pi bilan 3 qator
return label
}()
private let readButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("O'qish", for: .normal)
button.backgroundColor = .systemBlue
button.setTitleColor(.white, for: .normal)
button.layer.cornerRadius = 8
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupSubviews()
setupConstraints()
}
private func setupSubviews() {
view.addSubview(cardView)
cardView.addSubview(coverImageView)
cardView.addSubview(titleLabel)
cardView.addSubview(readButton)
}
private func setupConstraints() {
cardView.snp.makeConstraints { make in
make.center.equalToSuperview()
// Kenglik ekranining 90% qismi, lekin iPad uchun max 500 pt
make.width.equalToSuperview().multipliedBy(0.9).priority(.high)
make.width.lessThanOrEqualTo(500).priority(.required)
}
coverImageView.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview().inset(16)
// Image 16:9 aspect ratio
make.height.equalTo(coverImageView.snp.width).multipliedBy(9.0 / 16.0)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(coverImageView.snp.bottom).offset(16)
make.leading.trailing.equalToSuperview().inset(16)
// Label balandligi kontentga qarab o'sadi, limit 3 qator
}
readButton.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(20)
make.bottom.equalToSuperview().offset(-16) // Card'ni tugatish
make.centerX.equalToSuperview()
// Button kengligi cardning 60%, balandligi kamida 44pt
make.width.equalToSuperview().multipliedBy(0.6)
make.height.greaterThanOrEqualTo(44)
}
}
}
6. Amaliy loyiha 2: Image Gallery Grid {#project-gallery}
3 ta ustunli, rasmlar 1:1 (kvadrat) o'lchamda joylashadigan oddiy rasm galereyasi maketi. (Haqiqiy loyihalarda UICollectionView ishlatiladi, lekin bu SnapKit multipliedBy va aspectRatio ni tushunish uchun ajoyib mashq).
import UIKit
import SnapKit
class GalleryGridViewController: UIViewController {
private let containerView = UIView()
private var imageViews: [UIImageView] = []
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
// 3 ta rasm view yaratamiz
for _ in 0..<3 {
let iv = UIImageView()
iv.backgroundColor = .systemMint
iv.layer.cornerRadius = 8
imageViews.append(iv)
containerView.addSubview(iv)
}
setupSubviews()
setupConstraints()
}
private func setupSubviews() {
view.addSubview(containerView)
}
private func setupConstraints() {
containerView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.leading.trailing.equalToSuperview().inset(16)
}
let spacing: CGFloat = 10
for (index, imageView) in imageViews.enumerated() {
imageView.snp.makeConstraints { make in
make.top.bottom.equalToSuperview()
// Har bir rasm 1:1 aspect ratio
make.height.equalTo(imageView.snp.width)
if index == 0 {
make.leading.equalToSuperview()
} else {
let previousView = imageViews[index - 1]
make.leading.equalTo(previousView.snp.trailing).offset(spacing)
// Barcha rasmlar kengligi bir xil bo'lishi kerak
make.width.equalTo(previousView.snp.width)
}
if index == imageViews.count - 1 {
make.trailing.equalToSuperview()
}
}
}
}
}
Xulosa {#xulosa}
- Tengsizliklar (
greaterThanOrEqualTo,lessThanOrEqualTo) interfeysni moslashuvchan qilish va qat'iy buzilishlarning oldini olish uchun xizmat qiladi. - multipliedBy o'lchamlarni nisbiy (foizlarda) belgilashda foydali. iPad va iPhone o'rtasida adaptivlikni ta'minlaydi.
- Aspect Ratio — obyekt o'zining
widthvaheightqiymatlarini o'zaro bog'lash orqali rasm va videolarni to'g'ri ko'rsatish garovidir. - Bir nechta shartlarni (min va max) prioritetlar orqali muammosiz ishlatish mumkin.