ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS] SnapKit ์‚ฌ์šฉํ•˜๊ธฐ
    iOS 2022. 5. 10. 03:46

    SnapKit์ด๋ž€?

    ๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ๋กœ NSLayoutConstraint๋ฅผ ์‰ฝ๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์ฆ‰, ์งง์€ ์ฝ”๋“œ๋กœ ์˜คํ† ๋ ˆ์ด์•„์›ƒ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.

    ์˜คํ† ๋ ˆ์ด์•„์›ƒ ๋ฐ ์ œ์•ฝ ์กฐ๊ฑด์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” DSL (Domain-specific language).

    DSL์€?!

    Domain specific language (DSL)์€ ํŠน์ • ๋„๋ฉ”์ธ์„ ํ‘œํ˜„, ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ํŠน์ • ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ์–ธ์–ด์ด๋‹ค.

    SnapKit์˜ ๊ฒฝ์šฐ, ์˜คํ† ๋ ˆ์ด์•„์›ƒ ์ œ์•ฝ ์กฐ๊ฑด์— ๋Œ€ํ•ด ํ›จ์”ฌ ๋” ์ง๊ด€์ ์ด๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ๊ตฌ๋ฌธ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค.

     

     

    ๋จผ์ € ์ฝ”์ฝ”์•„ํŒŸ์œผ๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ํ•˜๊ธฐ!

    https://github.com/SnapKit/SnapKit

    pod 'SnapKit', '~> 5.6.0'

     

    ์ด๋ ‡๊ฒŒ import SnapKit์„ ํ•˜๋ฉด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ!

     

    ์ด์ œ SnapKit์„ ์‚ฌ์šฉํ•˜๋ฉด, ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์“ธ ํ•„์š”๊ฐ€ ์—†๋‹ค.

    translatesAutoresizingMaskIntoConstraints = false
    

    ์™œ๋ƒ?! SnapKit์ด ๋‚ด๋ถ€์—์„œ ์•Œ์•„์„œ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์—!

     

    ๐Ÿ’ก translatesAutoresizingMaskIntoConstraints

    UIView์˜ ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ๋กœ, ๋ทฐ์˜ autoresizing mask๋ฅผ AutoLayout constraints๋กœ ๋ณ€ํ™˜ํ• ์ง€์˜ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” bool ๊ฐ’์„ ์˜๋ฏธํ•œ๋‹ค.

    ๊ธฐ๋ณธ๊ฐ’์ด true์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ทฐ๋ฅผ ์ฝ”๋“œ๋กœ ์ง ๋‹ค๋ฉด ์ด ๊ฐ’์„ ํ•ญ์ƒ false๋กœ ์„ค์ •ํ•ด์•ผํ•œ๋‹ค.

     

     

    ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์˜ˆ์‹œ๋กœ ๋ณด์ž.

    child.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
      child.leadingAnchor.constraint(equalTo: parent.leadingAnchor),
      child.topAnchor.constraint(equalTo: parent.topAnchor),
      child.trailingAnchor.constraint(equalTo: parent.trailingAnchor),
      child.bottomAnchor.constraint(equalTo: parent.bottomAnchor),
    ])
    

     

    ์œ„ ์ฝ”๋“œ๋ฅผ SnapKit์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€ํ™˜ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

    child.snp.makeConstraints { make in
      make.leading.equalToSuperview()
      make.top.equalToSuperview()
      make.trailing.equalToSuperview()
      make.bottom.equalToSuperview()
    }
    

     

    SnapKit์€ ์‹œ์Šคํ…œ์˜ ๋ชจ๋“  UIView์— snp์ด๋ž€ namespace๋ฅผ ๋„์ž…ํ•œ๋‹ค.

    snp์€ makeConstraints(_:) ๋ฉ”์†Œ๋“œ์™€ ํ•จ๊ป˜ SnapKit์˜ ํ•„์ˆ˜ ์š”์†Œ์ด๋‹ค.

    ์œ„ ๋‘ ์ฝ”๋“œ๋Š” ๋น„์Šทํ•ด๋ณด์ด์ง€๋งŒ, ๊ฐ€๋…์„ฑ์ด ๋งค์šฐ ๊ฐœ์„ ๋˜์—ˆ๊ณ  ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    • SnapKit์˜ equalToSuperView() ๋•๋ถ„์—, parent๋ฅผ ์ฐธ์กฐํ•  ํ•„์š”๊ฐ€ ์ „ํ˜€ ์—†๋‹ค. ์ฆ‰, child๊ฐ€ ๋‹ค๋ฅธ parent view๋กœ ์ด๋™ํ•ด๋„ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
    • make๋Š” ๊ฑฐ์˜ ์˜์–ด์™€ ๋น„์Šทํ•œ ๊ตฌ๋ฌธ์„ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค. make ๊ตฌ๋ฌธ์€ “leading์ด superview์™€ ๋™์ผํ•˜๋„๋ก ๋งŒ๋“ค์–ด๋ผ”๋ผ๊ณ  ์ฝ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

     

    ์•„๋ž˜์™€ ๊ฐ™์ด ์“ฐ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

    child.snp.makeConstraints {
      $0.leading.equalToSuperview()
      $0.top.equalToSuperview()
      $0.trailing.equalToSuperview()
      $0.bottom.equalToSuperview()
    }

     

    Composability & Chaining

    SnapKit์˜ ๊ฐ€์žฅ ํฐ ํŠน์ง•์€ composition ๊ธฐ๋Šฅ์ด๋‹ค. ์ œ์•ฝ ์กฐ๊ฑด ์ž์ฒด ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋ชจ๋“  anchor๋“ค๋„ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

    ์œ„์—์„œ์˜ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

    child.snp.makeConstraints { make in
      make.leading.top.trailing.bottom.equalToSuperview()
    }
    

    ๋˜๋Š”, edges๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

    child.snp.makeConstraints { make in
      make.edges.equalToSuperview()
    }
    

    inset์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ฐ„๋‹จํ•˜๊ฒŒ chaining์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

    child.snp.makeConstraints { make in
      make.edges.equalToSuperview().inset(16)
    }
    

    ์œ„์™€ ๊ฐ™์ด Composability์™€ chaining์€ SnapKit์˜ ํ•ต์‹ฌ์œผ๋กœ, NSLayoutConstraints๋กœ๋Š” ์ ˆ๋Œ€ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์—†๋Š” ํ‘œํ˜„๋ ฅ์„ ์ œ๊ณตํ•œ๋‹ค.

     

     

    ์•„๋ž˜์˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž.

    // Before
    myLabel.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      myLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.45),
      myLabel.heightAnchor.constraint(equalToConstant: 45),
      myLabel.topAnchor.constraint(equalTo: viewProgress.bottomAnchor, constant: 32),
      myLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    ])
    
    // After
    myLabel.snp.makeConstraints { make in
      make.width.equalToSuperview().multipliedBy(0.45) // 1
      make.height.equalTo(45) // 2
      make.top.equalTo(viewProgress.snp.bottom).offset(32) // 3
      make.centerX.equalToSuperview() // 4
    }
    • 1 - ๋ผ๋ฒจ์˜ width๋ฅผ ์Šˆํผ๋ทฐ ๋„ˆ๋น„์˜ 0.45๋ฐฐ๋กœ ์„ค์ •
    • 2 - ๋ผ๋ฒจ์˜ height๋ฅผ 45๋กœ ์„ค์ •
    • 3 - ๋ผ๋ฒจ์˜ top์„ progress bar์˜ bottom์œผ๋กœ ์ œ์•ฝ์„ ์ฃผ๋˜, offset์€ 32๋งŒํผ ์„ค์ •
    • 4 - x์ถ•์„ ์Šˆํผ๋ทฐ์˜ x์ถ•์— ๋งž์ถฐ์„œ, ๋ผ๋ฒจ์„ ์ˆ˜ํ‰์œผ๋กœ ์ค‘์•™์— ๋ฐฐ์น˜

     

    ๋˜ ๋‹ค๋ฅธ ์˜ˆ์‹œ๋ฅผ ํ•˜๋‚˜ ๋ณด์ž.

    anotherLabel.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      anotherLabel.topAnchor.constraint(equalTo: myLabel.bottomAnchor, constant: 24),
      anotherLabel.leadingAnchor
        .constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
      anotherLabel.trailingAnchor
        .constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16)
    ])

     

    ์œ„์˜ ์ œ์•ฝ ์กฐ๊ฑด๋“ค์„ SnapKit์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

    make.top.equalTo(myLabel.snp.bottom).offset(24)
    make.leading.equalToSuperview().offset(16)
    make.trailing.equalToSuperview().offset(-16)
    

    ํ•˜์ง€๋งŒ ์‚ฌ์‹ค ์—ฌ๊ธฐ์„œ leading๊ณผ trailing anchor๊ฐ€ ๊ฐ™์€ ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ๋˜ ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

    anotherLabel.snp.makeConstraints { make in
      make.top.equalTo(lblTimer.snp.bottom).offset(24)
      make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16)
    }
    
    • leading, trailing์ด chain๋˜์–ด์žˆ๋‹ค.
    • ๋ทฐ์— ์ œ์•ฝ์„ ์ฃผ๊ธฐ ์œ„ํ•ด ํ•ญ์ƒ snp์„ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†๋‹ค. ์ด๋ฒˆ์—๋Š” UILayoutGuide๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

    ๋˜ํ•œ inset ์˜ต์…˜์ด ํ•ญ์ƒ ์ˆซ์ž์ผ ํ•„์š”๋Š” ์—†๋‹ค. UIEdgeInsets๋ฅผ ๋„ฃ์–ด๋„ ๋œ๋‹ค.

    make.leading.trailing.equalTo(view.safeAreaLayoutGuide)
      .inset(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))

     

    ๋˜ํ•œ, SnapKit์€ ํŠน์ • ์ œ์•ฝ ์กฐ๊ฑด์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

    // Before
    myButtons.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      myButtons.leadingAnchor.constraint(equalTo: anotherLabel.leadingAnchor),
      myButtons.trailingAnchor.constraint(equalTo: anotherLabel.trailingAnchor),
      myButtons.topAnchor.constraint(equalTo: anotherLabel.bottomAnchor, constant: 16),
      myButtons.heightAnchor.constraint(equalToConstant: 80)
    ])
    
    // After
    myButtons.snp.makeConstraints { make in
      make.leading.trailing.equalTo(anotherLabel)
      make.top.equalTo(anotherLabel.snp.bottom).offset(16)
      make.height.equalTo(80)
    }

    ์—ฌ๊ธฐ์„œ leading๊ณผ trailing์˜ constraint๊ฐ€ ๋‹จ์ˆœํžˆ anotherLabel๊ณผ ๊ฐ™๋‹ค๊ณ  ์ •์˜ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด, SnapKit์€ ์•Œ์•„์„œ ์ถ”๋ก ํ•˜์—ฌ ์ œ์•ฝ์„ ์„ค์ •ํ•œ๋‹ค.

     

     

    ์•„๋ž˜ ์˜ˆ์‹œ์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, otherView์˜ ํŠน์ˆ˜์„ฑ์€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.

    SnapKit์€ ๊ด€๊ณ„์—์„œ ์ฒซ๋ฒˆ์งธ ๋ทฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์–ด๋–ค ์ข…๋ฅ˜์˜ ์ œ์•ฝ ์กฐ๊ฑด์„ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค!

    // Original Code
    view.snp.makeConstraints { make in
      make.width.equalTo(otherView.snp.width)
      make.centerX.equalTo(otherView.snp.centerX)
    }
    
    // Could be written as 1:
    view.snp.makeConstraints { make in
      make.width.equalTo(otherView)
      make.centerX.equalTo(otherView)
    }
    
    // Could be written as 2:
    view.snp.makeConstraints { make in
      make.width.centerX.equalTo(otherView)
    }

     

     

    To be continue..

     

     

    ์ฐธ๊ณ  ๋ฌธ์„œ

     

    SnapKit for iOS: Constraints in a Snap

    In this tutorial you’ll learn about SnapKit, a lightweight DSL (domain-specific language) to make Auto Layout and constraints a breeze to work with.

    www.raywenderlich.com

     

    ๋Œ“๊ธ€

Designed by Tistory.