# 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
1. [Tengsizlik Constraint'lar (Inequality)](#inequality)
2. [multipliedBy va dividedBy](#multipliers)
3. [Aspect Ratio (Tomonlar nisbati)](#aspect-ratio)
4. [Minimum va Maximum o'lcham strategiyasi](#min-max-strategy)
5. [Amaliy loyiha: Responsive Card Layout](#project-card)
6. [Amaliy loyiha 2: Image Gallery Grid](#project-gallery)
7. [Xulosa](#xulosa)
8. [Manbalar](#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.

```text
+-----------------------+
|  SuperView            |
|                       |
|  [ View (Min 44pt) ]  | <-- Balandligi kamida 44pt, lekin kontent ko'paysa o'sishi mumkin
|                       |
+-----------------------+
```

### Kod misoli

```swift
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 doim `greaterThanOrEqualTo(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%) |

```swift
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.

```text
 16:9 Video Aspect Ratio           1:1 Square
+-----------------------+         +--------+
|                       |         |        |
|                       |         |        |
|                       |         +--------+
+-----------------------+         width = height
 height = width * (9/16)
```

```swift
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.

```swift
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.

```swift
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).

```swift
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 `width` va `height` qiymatlarini 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.

## Manbalar {#manbalar}

- [SnapKit Rasmiy Dokumentatsiyasi](https://github.com/SnapKit/SnapKit)
- [Apple Auto Layout Guide: Priorities and Constraints](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintBasedLayout.html)
- [Apple Human Interface Guidelines (HIG)](https://developer.apple.com/design/human-interface-guidelines/)
