관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 4. Storyboard로 UI 구현 기본기 - Xib, Nib 개념, 커스텀 뷰 본문

iOS 응용 (swift)

[iOS - swift] 4. Storyboard로 UI 구현 기본기 - Xib, Nib 개념, 커스텀 뷰

jake-kim 2023. 3. 3. 01:11

* Storyboard로 UI 구현 기본기 목차 참고

xib, nib 란?

  • XIB(Xcode Interface Builder), NIB(Next Interface Builder)
    • XIB는 Xcode에서 제공하는 시각적 에디터를 의미하며 View라는 파일을 선택하여 만들면 .xib 확장자명을 가지는 파일이 생성 (xml 형태)
    • NIB는 XIB가 컴파일되어 메모리에 로드할 때 사용되는 파일을 NIB라고 명칭
  • 주의 - storyboard는 .xib가 아님
    • storyboard 파일이 컴파일되면 .storyboardc로 변환
  • xib가 빌드되면 nib로 변경되고 이 파일은 App Bundle 디렉토리에 저장되어 코드 베이스에서 이 파일을 사용할 땐 bundle에서 로드하여 사용

xib 커스텀 뷰 만드는 방법

  • view 선택

  • 생성된 .xib 파일

 

  • .xib 파일과 연결된 .swift 파일도 추가 
    • MyView.swift 파일
import UIKit

@IBDesignable
class MyView: UIView {

}
  • xcode에서 .xib 파일을 열면 viewController 처럼 크게 존재

.xib 파일 초기화

  • File's Owner 설정
    • MyView로 입력(위에서 만든 MyView.swift를 의미)

  • Layout Margins -> safe area Relative Margins 해제

  • size > freeform으로 설정
    •  해당 속성은 단순히 개발자에게 에디터에서 보여지는 방식에 관한 옵션 
    • 디폴트는 inferred이며, inferred는 노치와 같은 디바이스의 모양을 표시해주는데, 커스텀뷰는 사각형의 뷰만 있으면 되므로 freeform으로 설정

  • 드래그하여 적당한 사이즈가 되도록 크기를 수정

  • 테스트를 위해 UILabel 하나와 backgroundColor 변경
    • autolayout은 4방향 모두 0으로 설정
    • 디폴트는 safe area 기준으로 autolayout되므로 superview 기준으로 변경

(label의 backgroundColor 색상도 변경)

  • .xib 쪽은 완성되었고, .swift파일에서 이 .xib 파일을 사용하도록 구현
    • 아래 내용에서 계속
import UIKit

@IBDesignable
class MyView: UIView {

}
  • label 인터페이스 연결
import UIKit

@IBDesignable
class MyView: UIView {
    @IBOutlet weak var label: UILabel!
}
  • 코드에서 초기화하는 init(frame:)과 xib 초기화에 사용되는 init?(coder:) 선언
    • 둘 다 위에서 구현한 .xib파일을 사용하여 초기화해야하므로 xibSetup()을 호출
override init(frame: CGRect) {
    super.init(frame: frame)
    xibSetup()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    print("coder: aDecoder")
    xibSetup()
}
  • xibSetup() 메소드에서는 xib를 컴파일하면 생성되는 .nib 파일을 번들에서 가져오는 메소드를 호출하는데 이는 여러 뷰에서 사용되므로 UIView를 extension하여 구현
extension UIView {
    func loadViewFromNib(nib: String) -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: nib, bundle: bundle)
        return nib.instantiate(withOwner: self, options: nil).first as? UIView
    }
}
  • xibSetup에서 이 메소드를 호출하여 구현
func xibSetup() {
    guard let view = loadViewFromNib(nib: "MyView") else { return }
    view.frame = bounds
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    addSubview(view)
}
  • 또는 autolayout을 사용한다면 아래처럼 구현
    • 단, 이렇게 구현하면 사용하는쪽에서 storyboard에서 편집할 시점에서는 뷰 모양이 정해지지 않으므로 autoresizingMask 사용 지향 (autolayout을 사용하면 앱을 실행할 때 정해짐)
func xibSetup() {
    guard let view = loadViewFromNib(nib: "MyView") else { return }
    view.translatesAutoresizingMaskIntoConstraints = false
    addSubview(view)
    NSLayoutConstraint.activate([
        leadingAnchor.constraint(equalTo: view.leadingAnchor),
        trailingAnchor.constraint(equalTo: view.trailingAnchor),
        bottomAnchor.constraint(equalTo: view.bottomAnchor),
        topAnchor.constraint(equalTo: view.topAnchor),
    ])
}

(커스텀뷰 구현 완료)

.xib 커스텀뷰 사용 방법

  • storyboard에서 uiview를 추가 및 센터 정렬

  • class 입력

  • MyView 사이즈가 정해지지 않은 상태이므로
    • 우측 하단의 intrinsic content size > placeholder로 변경하여 커스텀뷰의 사이즈만큼 사이즈가 결정되도록 설정

  • 아래처럼 커스텀 뷰의 내용이 안보이면 Xcode를 껐다 키기
    • 만약 custom view에서 정의한 label의 사이즈보다 크게 표시되면 위에서 설정했던 intrinsic content size를 다시 default로 변경 후 placeholder로 변경되면 정상동작

(완료)

* 전체 코드: https://github.com/JK0369/ExXibView

 

* 참고

https://ios-development.tistory.com/391

https://stackoverflow.com/questions/32819768/what-is-the-difference-between-inferred-and-freeform-in-xcode-storyboard

Comments