# SnapKit 5: Priority Tizimi va Content Hugging — Qaysi view cho'ziladi, qaysi siqiladi?

> **Holat:** 2026-yil oktabr holatiga ko'ra, murakkab va o'zgaruvchan interfeyslarda (masalan, chat ekranlari, dinamik ro'yxatlar) constraint'lar ziddiyatini (conflict) oldini olish uchun Priority, Hugging va Compression Resistance tushunchalarini mukammal bilish shart.

## Mundarija
1. [SnapKit Priority API](#snapkit-priority-api)
2. [Nima uchun 999 priority eng muhim?](#999-priority)
3. [Content Hugging Priority (CHP)](#chp)
4. [Content Compression Resistance (CCRP)](#ccrp)
5. [Vizual diagrammalar](#diagrammalar)
6. [Amaliy loyiha: Telegram uslubidagi Chat Row](#telegram-chat)
7. [Amaliy loyiha 2: Price Tag (Narx belgisi)](#price-tag)
8. [Xulosa](#xulosa)
9. [Manbalar](#manbalar)

## 1. SnapKit Priority API {#snapkit-priority-api}

Auto Layout tizimi har bir constraint uchun ma'lum bir **muhimlik darajasini** (priority) talab qiladi. Bir nechta ziddiyatli (conflict) constraint'lar yuzaga kelsa, tizim doim **priority'si yuqori** bo'lganini bajaradi.

SnapKit'da priority o'rnatish juda oson. Buning uchun constraint oxirida `.priority()` funksiyasidan foydalanamiz.

| Priority | Son qiymati | SnapKit API | Izoh |
| :--- | :--- | :--- | :--- |
| **Required** | `1000` | `.priority(.required)` | Majburiy constraint. Buzilsa crash yoki runtime warning beradi. |
| **High** | `750` | `.priority(.high)` | Yuqori ustuvorlik, ko'pincha UI elementlarning tabiiy o'lchamini saqlash uchun. |
| **Medium** | `500` | `.priority(.medium)` | O'rta ustuvorlik. |
| **Low** | `250` | `.priority(.low)` | Eng past ustuvorlik. Qolgan hamma narsa bajarilgandan keyin ishlaydi. |
| **Custom** | `999` (va h.k) | `.priority(999)` | Aynan o'zimiz kiritgan raqam. |

**Misol:**
```swift
import UIKit
import SnapKit

let boxView = UIView()

func setupConstraints() {
    boxView.snp.makeConstraints { make in
        make.top.equalToSuperview().offset(20)
        make.width.equalTo(200).priority(.high) // 750
        make.height.equalTo(150).priority(250)  // custom yoki .low
    }
}
```

## 2. Nima uchun 999 priority eng muhim? {#999-priority}

> **Senior eslatmasi:** Agar siz dinamik o'zgaradigan yoki animatsiya qilinadigan constraint yozsangiz, unga doim `1000` (`.required`) o'rniga `999` priority bering!

**Sababi:**
- `.required` (1000) constraint'lar hech qachon buzilishi mumkin emas. Agar Auto Layout hisoblashda biroz xatoga yo'l qo'ysa yoki o'tish jarayonida (transition) 1-2 piksellik ziddiyat chiqsa, xunuk Xcode konsol warning'lari ("Unable to simultaneously satisfy constraints") ko'rasiz.
- **999 priority** eslatadi: bu constraint deyarli `required`, lekin agar biron kutilmagan vaziyat bo'lsa (masalan keyboard chiqib ekran qisilganda), tizim shunchaki bu constraint'ni e'tiborsiz qoldiradi va **Crash bo'lmaydi, Warning ham chiqmaydi**.

```swift
make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).priority(999)
```

## 3. Content Hugging Priority (CHP) — Cho'zilishga qarshilik {#chp}

**Content Hugging Priority (CHP)** — bu View'ning o'z "tabiiy o'lchami"dan (intrinsic content size) kattalashib, **cho'zilib ketishiga qarshilik kuchi**.

- **Yuqori CHP:** View o'z o'lchamini mahkam ushlab turadi, **cho'zilMAYDI**.
- **Past CHP:** View bo'sh joyni to'ldirish uchun **cho'ziLADI**.

Tasavvur qiling, 2 ta Label yonma-yon joylashgan va butun ekranni to'ldirishi kerak. Qaysi biri bo'sh joyni egallaydi? CHP'si past bo'lgani!

```swift
let leftLabel = UILabel()
let rightLabel = UILabel()

func setupConstraints() {
    // SnapKit usulida CHP o'rnatish
    leftLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) 
    // yoki
    // leftLabel.snp.contentHuggingHorizontalPriority = 750 (bu kamroq ishlatiladi)
    
    rightLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
    
    // leftLabel qisqa bo'lib qoladi, rightLabel esa qolgan joyni to'ldirib cho'ziladi.
}
```

## 4. Content Compression Resistance Priority (CCRP) — Siqilishga qarshilik {#ccrp}

**Content Compression Resistance Priority (CCRP)** — bu View'ning o'z "tabiiy o'lchami"dan kichiklashib, **siqilib qolishiga qarshilik kuchi**.

- **Yuqori CCRP:** View **siqilMAYDI**, uning matni to'liq ko'rinadi.
- **Past CCRP:** View **siqiLADI**, masalan UILabel matni oxiriga `...` tushib qisqaradi.

Agar joy yetishmasa, tizim qaysi view'ni ezib qo'yishini CCRP orqali hal qiladi.

```swift
let titleLabel = UILabel()
let timeLabel = UILabel()

func setupConstraints() {
    // timeLabel'ni hech qachon siqma, u doim to'liq (masalan "14:25") ko'rinishi shart!
    timeLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
    
    // titleLabel'ni esa joy yetmasa qisqartirib yuborsa bo'ladi (masalan "Assalomu ala...")
    titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
}
```

## 5. Vizual diagrammalar {#diagrammalar}

```text
[   CHO'ZILISH (Hugging) JARAYONI   ]

Bo'sh joy ko'p. Qaysi biri cho'ziladi?
|-[ Name (CHP: 750) ]-[ Message (CHP: 250) ]-----------------------|
Natija:
|-[ Name ]-[ Message                                              ]|
Sabab: Message'ning Hugging priority'si past, shuning uchun u bo'sh joyni o'rab oladi.


[   SIQILISH (Compression Resistance) JARAYONI   ]

Joy yetishmayapti. Qaysi biri eziladi?
|-[ Long Title Text (CCRP: 250) ]-[ 14:30 (CCRP: 1000) ]|
Natija:
|-[ Long Title T... ]-[ 14:30 ]|
Sabab: Time label'ning Resistance'i (1000), uni siqib bo'lmaydi. Shuning uchun Title qisqaradi.
```

## 6. Amaliy loyiha: Telegram uslubidagi Chat Row {#telegram-chat}

Telegram chatlar ro'yxatini ko'z oldingizga keltiring:
- Avatar doim 50x50.
- Vaqt (`14:25`) va Unread badge doim o'ng tomonda va aslo ezilmaydi (High CCRP).
- Ism va Oxirgi xabar esa qolgan joyni egallaydi.

```swift
import UIKit
import SnapKit

class TelegramChatCell: UITableViewCell {
    
    let avatarImageView = UIImageView()
    let nameLabel = UILabel()
    let messageLabel = UILabel()
    let timeLabel = UILabel()
    let unreadBadge = UILabel()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupSubviews()
        setupConstraints()
    }
    
    required init?(coder: NSCoder) { fatalError() }
    
    @MainActor
    private func setupSubviews() {
        [avatarImageView, nameLabel, messageLabel, timeLabel, unreadBadge].forEach {
            contentView.addSubview($0)
        }
        
        nameLabel.font = .boldSystemFont(ofSize: 16)
        messageLabel.textColor = .gray
        timeLabel.textColor = .lightGray
        timeLabel.font = .systemFont(ofSize: 12)
        
        // --- Priority Sozlamalari ---
        
        // Time label va Badge aslo siqilmasligi kerak
        timeLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
        unreadBadge.setContentCompressionResistancePriority(.required, for: .horizontal)
        
        // Name label siqilishiga qattiqroq qarshilik qiladi, xabarga nisbatan
        nameLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
        messageLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
    }
    
    @MainActor
    private func setupConstraints() {
        avatarImageView.snp.makeConstraints { make in
            make.left.equalToSuperview().offset(16)
            make.centerY.equalToSuperview()
            make.size.equalTo(50) // Qat'iy o'lcham
        }
        
        timeLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.right.equalToSuperview().inset(16)
            // Kenglik berilmaydi, o'z contentiga qarab o'sadi, siqilmaydi
        }
        
        nameLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.left.equalTo(avatarImageView.snp.right).offset(12)
            make.right.lessThanOrEqualTo(timeLabel.snp.left).offset(-8)
        }
        
        unreadBadge.snp.makeConstraints { make in
            make.bottom.equalToSuperview().inset(12)
            make.right.equalToSuperview().inset(16)
            make.height.equalTo(20)
            make.width.greaterThanOrEqualTo(20)
        }
        
        messageLabel.snp.makeConstraints { make in
            make.bottom.equalToSuperview().inset(12)
            make.left.equalTo(avatarImageView.snp.right).offset(12)
            make.right.equalTo(unreadBadge.snp.left).offset(-8)
        }
    }
}
```

## 7. Amaliy loyiha 2: Price Tag (Narx belgisi) {#price-tag}

Mahsulot narxi kartochkasida ko'pincha "Asl narx" (ustidan chizilgan), "Chegirmali narx" va "Foiz" yonma-yon turadi.

```swift
import UIKit
import SnapKit

class PriceTagView: UIView {
    let discountPriceLabel = UILabel()
    let originalPriceLabel = UILabel()
    let percentBadge = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupSubviews()
        setupConstraints()
    }
    
    required init?(coder: NSCoder) { fatalError() }
    
    @MainActor
    private func setupSubviews() {
        addSubview(discountPriceLabel)
        addSubview(originalPriceLabel)
        addSubview(percentBadge)
        
        discountPriceLabel.font = .boldSystemFont(ofSize: 24)
        
        originalPriceLabel.textColor = .gray
        // Ustidan chizilgan text funksiyasi bu yerda yozilardi
        
        percentBadge.backgroundColor = .red
        percentBadge.textColor = .white
        
        // Qoidalar:
        // 1. Foiz (badge) doim ko'rinishi shart (ezilmaydi)
        percentBadge.setContentCompressionResistancePriority(.required, for: .horizontal)
        
        // 2. Original narx kerak bo'lsa qisqarib ketishi mumkin
        originalPriceLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        
        // 3. Discount narx muhimroq, uni siqish qiyinroq
        discountPriceLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
    }
    
    @MainActor
    private func setupConstraints() {
        discountPriceLabel.snp.makeConstraints { make in
            make.left.top.bottom.equalToSuperview()
        }
        
        originalPriceLabel.snp.makeConstraints { make in
            make.left.equalTo(discountPriceLabel.snp.right).offset(8)
            make.lastBaseline.equalTo(discountPriceLabel.snp.lastBaseline)
        }
        
        percentBadge.snp.makeConstraints { make in
            make.left.equalTo(originalPriceLabel.snp.right).offset(8)
            make.right.lessThanOrEqualToSuperview()
            make.centerY.equalTo(discountPriceLabel)
        }
    }
}
```

## Xulosa {#xulosa}

- `.priority(999)` — Auto Layout kutilmagan constraint conflict'larida ilovani crash qilmasligi yoki warning bermasligi uchun qilingan eng yaxshi "tricky" (ayyorona) yechim.
- **Hugging (cho'zilishga qarshi)** va **Compression Resistance (siqilishga qarshi)** xususiyatlari interfeysning har qanday ekran o'lchamlariga moslashuvchan (adaptive) bo'lishini ta'minlaydi.
- SnapKit yordamida standart UIKit funksiyalari (masalan, `setContentHuggingPriority`) mukammal sinergiyada ishlaydi.

## Manbalar {#manbalar}
- [SnapKit Rasmiy Dokumentatsiyasi](http://snapkit.io/docs/)
- [Apple Auto Layout Guide - Layout Priorities](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintBasedLayout.html)
