Azimjon Abdurasulov

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

  1. Tengsizlik Constraint'lar (Inequality)
  2. multipliedBy va dividedBy
  3. Aspect Ratio (Tomonlar nisbati)
  4. Minimum va Maximum o'lcham strategiyasi
  5. Amaliy loyiha: Responsive Card Layout
  6. Amaliy loyiha 2: Image Gallery Grid
  7. Xulosa
  8. 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 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.

MetodMa'nosiMisol
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 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}

Markdown manba

iOS Lessons