본문 바로가기

IOS

Swift - Snapkit

최근에 SwiftUI 프로젝트를 진행 하다보니 UIKit 에 대해 소홀해졌다..

Snapkit 에 대해 겉핥기로 알고 있었기에 이번 기회에 다시 Snapkit 을 공부 해보도록 하자.

 * 최대한 하나씩 하나씩 설명할려고 하는데 중복적인 내용은 제외 하겠습니다


https://github.com/SnapKit/SnapKit

 

GitHub - SnapKit/SnapKit: A Swift Autolayout DSL for iOS & OS X

A Swift Autolayout DSL for iOS & OS X. Contribute to SnapKit/SnapKit development by creating an account on GitHub.

github.com

pod 'SnapKit'

1. View  

import SnapKit
import UIKit

class ViewController: UIViewController {

     private let contentView: UIView = {
       let view = UIView()
        view.backgroundColor = UIColor.red
        return view
     }()
    
	 override func viewDidLoad() {
        super.viewDidLoad()
         initView()
         initConstraint()
     }
     
     private func initView() {
        view.addSubview(contentView)
    }

    private func initConstraint() {
    	contentView.snp.makeConstraints {
            make in
//            make.top.equalTo(view.safeAreaLayoutGuide.snp.topMargin) // safe area
            make.top.equalToSuperview()
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(100)
        }
    }
}

상단에 UIView를 선언함에 동시에 그에 대한 옵션을 추가 할수가 있다.

addSubview를 통해 뷰를 추가하고 그에따른 제약조건을 추가한다.

 

1. make.top.equipToSuperView()

   -> contentView 의 상단은 contentView의 superView 상 Top 으로 추가한다

   -> safeArea를 무시하고 최상단까지 올라갈수 있는데 (상태창) 그게 싫은경우 다음과 같은 코드를 추가 할수 있다. 

   -> make.top.equipTo(view.safeAreaLayoutGuide.snp.topMargin) 

2. make.leading.trailing.equalToSuperview()

   -> contentView의 좌우측은 contentView의 superView 상 좌우측 으로 붙인다

   -> 만약, 4방향 다 붙이고 싶은경우 (꽉채움) 다음과 같은 코드를 추가 할수 있다.  (edges)

   -> make.edges.equalToSuperview()

3. make.height.equipTo(100)

    -> ContentView 의 높이는 100으로 설정 한다.


2.  View 안에 내용 추가

import SnapKit
import UIKit

class ViewController: UIViewController {

     private let headerView: UIView = {
       let view = UIView()
        view.backgroundColor = UIColor.red
        return view
    }()
    
    private let label: UILabel = {
        let label = UILabel()
        label.text = "내일은"
        return label
    }()
    
    private let label2: UILabel = {
        let label = UILabel()
        label.text = "월요일이다."
        return label
    }()
    
	 override func viewDidLoad() {
        super.viewDidLoad()
         initView()
         initConstraint()
     }
     
     private func initView() {
        headerView.addSubview(label)
        headerView.addSubview(label2)
        
        view.addSubview(headerView)
    }

    private func initConstraint() {
    	 headerView.snp.makeConstraints {
            make in
            make.top.equalTo(view.safeAreaLayoutGuide.snp.topMargin) // safe area
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(100)
        }
        
        label.snp.makeConstraints {
            make in
            make.top.equalTo(headerView.snp.top).offset(20)
            make.leading.equalTo(headerView.snp.leading).offset(20)
        }

        label2.snp.makeConstraints {
            make in
            make.top.equalTo(label.snp.bottom).offset(10)
            make.leading.equalTo(label.snp.leading)
        }
    }
}

상단에 UIView 와 UILabel 를 추가하고

내용을 추가할 뷰에 먼저 라벨을 추가하고, 추가한 뷰를 메인뷰에 추가한다. 그리고 제약조건을 추가한다.

 

1. make.top.equalTo(headerView.snp.top).offset(20)

  -> 첫번째 라벨 은 superView로 속해있는 headerView 상단에 맞추고 offset를 이용하여 20 만큼의 마진을 추가한다.

2. make.leading.equalTo(headerView.snp.leading).offset(20)

   -> 첫번째 라벨 은 superView로 속해있는 headerView 좌측에 맞추고 offset를 이용하여 20 만큼의 마진을 추가한다.

 

3. make.top.equalTo(label.snp.bottom).offset(10)

  -> 두번째 라벨의 상단은 첫번째 라벨의 하단에 맞추고 offset를 이용하여 10 만큼의 마진을 추가한다.

4. make.leading.equalTo(label.snp.leading)

   -> 두번째 라벨의 좌측은 첫번째 라벨의 좌측 수치에 맞게 조절한다 (만약 첫번째 라벨 좌측 값 변동시 그 값을 따라감)


3. ScrollView

import UIKit
import SnapKit

class SecondViewController: UIViewController {

    	let contentView = UIView()
        let headerView1: UIView = {

            let view = UIView()
            view.backgroundColor = UIColor.green

            return view
        }()

        let headerView2: UIView = {

            let view = UIView()
            view.backgroundColor = UIColor.red

            return view
        }()

        let headerView3: UIView = {

            let view = UIView()
            view.backgroundColor = UIColor.blue

            return view
        }()

        let scrollView: UIScrollView = {
            let scrollView = UIScrollView()
            scrollView.isScrollEnabled = true
            scrollView.showsVerticalScrollIndicator = false

            return scrollView
        }()
        
        override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        initView()
        initConstraint()
    }
    
    private func initView() {
        
        let _ = [headerView1, headerView2 , headerView3].map {
            contentView.addSubview($0)
        }
        
        scrollView.addSubview(contentView)
        view.addSubview(scrollView)
    }

    private func initConstraint() {
        
        scrollView.snp.makeConstraints {
            make in
            make.edges.equalTo(0)
        }

        headerView1.snp.makeConstraints {
            make in
            make.width.equalToSuperview()
            make.height.equalTo(300)
            make.top.equalTo(contentView.snp.top)
        }
        
        headerView2.snp.makeConstraints {
            make in
            make.width.equalToSuperview()
            make.height.equalTo(300)
            make.top.equalTo(headerView1.snp.bottom).offset(0)
        }

        headerView3.snp.makeConstraints {
            make in
            make.width.equalToSuperview()
            make.top.equalTo(headerView2.snp.bottom).offset(0)
            make.bottom.equalToSuperview()
        }
        
        contentView.snp.makeConstraints {
            make in
            make.width.equalToSuperview()
            make.edges.equalTo(0)
            make.height.equalTo(view.frame.height + 100)
        }
    }

 }

 

Scrollview 에 내용에 들어갈만한 뷰(header1~3) 를 가지고있는 한개의 뷰를 생성하여 (contentView) 를 ScrollView 에 추가한다.

그리고 그 ScrollView뷰를 메인뷰에 추가한다. 그리고 제약조건을 추가한다.

 

1. make.edges.equalTo(0)

   -> ScrollView의 top, bottom, leading, trailing 부모뷰에 붙인다

 

2. make.width.equipToSuperView()

   -> 뷰의 넓이는 부모뷰 넓이와 동일하게 맞춘다.

 

3. make.height.equipTo(300)

   -> 뷰의 크기는 300 으로 제한한다


4.  Animation (Button Click)

import UIKit
import SnapKit

class ViewController: UIViewController {

    var isViewHidden = true

	private let button: UIButton = {
       let button = UIButton()
        button.setTitle("button", for: .normal)
        button.setTitleColor(UIColor.red, for: .normal)
        button.addTarget(self, action: #selector(footerAnimation) , for: .touchUpInside)
        return button
    }()
    
    private let footerView: UIView = {
       let view = UIView()
        view.backgroundColor = UIColor.blue
        return view
    }()
    
        override func viewDidLoad() {
        super.viewDidLoad()
        
        initView()
        initConstraint()
    }
    
    private func initView() {
        view.addSubview(button)
        view.addSubview(footerView)
    }
    
    @objc private func footerAnimation() {
      isViewHidden.toggle()
      
      UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: { [self] in
              footerView.snp.updateConstraints {
                  $0.height.equalTo(isViewHidden ? 0 : 100)
            }
              view.layoutIfNeeded()
          })
          
    }
}

버튼과 뷰를 생성하고 버튼 클릭시에 isViewHidden 값이 변하며 그에 대해 제약조건을 변경 시키고 애니메이션을 추가 합니다

 

1. updateConstraints (height.equalTo)

   -> 해당 뷰의 제약조건을 변경합니다. 

2. layoutIfNeeded()

   -> animation 관련 작업을 위해 뷰를 업데이트 합니다.


Snapkit 으로 작업한 내용은 preview 로 확인 할수 없기에 SwiftUI 파일 생성하여 UIViewRepresentable 이용하여 표시하면 볼수 있습니다.

 

내용 추가는 계속계속할 예정입니다!