iOS View 체계
우리가 iOS 애플리케이션 화면에서 보는 콘텐츠는 윈도우와 뷰를 사용해 나타납니다.
원하는 모양으로 화면을 구성하고, 화면 위에서 일어나는 제스처를 관리하기 위해 뷰에 대해 이해하는 것은 매우 중요합니다.
학습 목표
1. 뷰 계층(view hierarchy)구조와 계층에 포함된 뷰가 어떻게 행동하는지 이해합니다.
2. 뷰 계층을 생성하고 관리하는 방법을 이해합니다.
3. 뷰의 좌표계를 이해합니다.
핵심 키워드
- View hierarchy
- SuperView/SubView
- Interface Builder
- Frame/Bounds
학습하기
뷰의 기본적인 역할
iOS에서 화면에 애플리케이션의 콘텐츠를 나타내기 위해 윈도우와 뷰를 사용합니다. 윈도우는 그 자체로 콘텐츠를 표현할 수 없지만 애플리케이션의 뷰를 위한 컨테이너 역할을 합니다. 뷰는 UIView 클래스 또는 UIView 클래스의 하위클래스(Subclass)의 인스턴스로 윈도우의 한 영역에서 콘텐츠를 보여줍니다. 뷰가 나타낼 수 있는 콘텐츠는 이미지, 문자, 도형 등과 같이 다양합니다. 뷰는 또 다른 뷰를 관리하고 구성하기 위해 사용되기도 합니다.
뷰는 제스처 인식기(gesture recognizer)를 사용하거나 직접 터치 이벤트를 처리할 수 있습니다. 또한 뷰 계층(view hierarchy)구조에서 부모뷰(parent view)는 자식뷰(child view)의 위치와 크기를 관리합니다.
나타내고자 하는 유형의 콘텐츠에 적합한 뷰를 여러 개 사용하여 뷰 계층(view hierarchy)구조를 구성하고 이를 통해 콘텐츠를 보여주는 것이 좋습니다. 예를 들어 UIKit에는 이미지, 텍스트 그리고 다른 유형의 콘텐츠를 나타내는 뷰가 포함되어 있습니다.
먼저 '뷰 계층(view hierarchy)'에 대해서 알아봅시다.
뷰 계층(View hierarchy)
뷰 계층구조와 서브뷰 관리
뷰는 자신의 콘텐츠를 보여주는 것과 더불어, 다른 뷰를 위한 컨테이너로써의 역할도 합니다. 하나의 뷰가 다른 뷰를 포함할 때, 두 뷰 사이에 부모-자식 관계가 생성됩니다. 해당 관계에서는 자식뷰는 서브뷰(subview)로, 부모뷰는 슈퍼뷰(superview)로 불려집니다. 부모-자식 관계 형성은 애플리케이션의 시각적 모습과 동작 모두에 영향을 미칩니다.
아래 예시 그림들을 통해서 슈퍼뷰와 서브뷰의 관계가 시각적으로 콘텐츠에 어떤 영향을 미치는지 알아봅시다.
1. 슈퍼뷰와 서브뷰의 관계에서 서브뷰가 불투명할 경우 아래 그림과 같이 슈퍼뷰가 서브뷰에 가려집니다.
2. 서브뷰가 반투명할 경우 서브뷰와 슈퍼뷰의 콘텐츠가 서로 섞여 화면에 보여지게 됩니다.
아래 그림과 같이 원래 노란색이었던 뷰가 슈퍼뷰의 빨간색과 섞여 주황색으로 화면에 보이게 됩니다.
3. 슈퍼뷰는 하나의 배열 안에 서브뷰를 순서대로 저장합니다. 만약 하나의 슈퍼뷰에 포함된 두 서브뷰가 서로 겹치게 되면,
나중에 추가된(또는 서브뷰 배열의 끝으로 옮겨진) 서브뷰가 맨 위에 보여지게 됩니다.
뷰 계층의 생성과 관리
OS 애플리케이션에서 뷰 계층을 만드는 방법에는 인터페이스 빌더를 이용하는 방법과 코드를 작성하는 방법이 있습니다.
코드작성 방식을 사용할 경우 서브뷰를 부모뷰에 추가하기 위해, 부모뷰의 addSubView(_:) 메서드를 호출합니다. 이 메서드는 해당 서브뷰를 서브뷰 목록의 마지막에 추가합니다. 부모뷰의 서브뷰를 제거하기 위해서는 서브뷰의 removeFromSuperView() 메서드를 호출합니다. 이 외에도 서브뷰를 부모뷰 목록의 중간에 삽입하기 위해 insertSubview(_:at:), 부모뷰 내에 이미존재하는 서브뷰를 정렬하기 위해 bringSubView(toFront:), sendSubview(toBack:) 등의 메서드들을 호출할 수 있습니다.
이번에는 두 방법을 비교해 보며 뷰 계층을 생성하고 관리하는 법을 살펴봅시다. (서브뷰를 시각적으로 확인하기 위해 서브뷰의 색상을 초록색으로 변경하는 과정이 포함되어 있습니다.)
아래 예제를 따라하며 뷰 계층구조를 처음부터 구성해봅시다.
• 1-1. 뷰를 생성하여 슈퍼뷰의 서브뷰로 추가하기 (인터페이스 빌더)
• 1-2. 뷰를 생성하여 슈퍼뷰의 서브뷰로 추가하기 (코드작성 방식)
◦ 서브뷰를 부모뷰에 추가하기 위해서는 부모뷰의 addSubview 메서드를 호출합니다. 이 메서드는 해당 서브뷰를 부모뷰의 서브뷰 목록의 마지막에 추가합니다. (코드에서 view는 메인 스토리보드에 있는 ViewController의 SuperView를 나타냅니다)
• 2-1. 서브뷰 제거하기 (인터페이스 빌더)
• 2-2. 서브뷰 제거하기 (코드작성 방식)
뷰의 좌표계
UIKit에서 기본이 되는 좌표계는 좌측 상단 모서리를 원점으로 하며, 원점으로부터 아래쪽, 오른쪽 방향으로 확장됩니다. 좌표값은 해상도와 상관없이 콘텐츠의 위치를 잡는 부동소수점을 사용하여 나타냅니다.
프레임과 바운드
iOS의 좌표체계의 시작은 왼쪽 위부터 시작입니다. 즉, 제일 왼쪽의 제일 위의 지점이 (0, 0)입니다. 또, 수평축은 x로, 수직축은 y로 표현합니다.
뷰의 프레임(frame)은 뷰의 크기와 위치를 슈퍼뷰의 좌표계를 기준으로 나타냅니다. 바운드(bounds)는 뷰의 크기와 위치를 해당 뷰 자신의 좌표계를 기준으로 나타냅니다. 아래 그림을 통해 서브뷰의 프레임과 바운드가 어떤 차이가 있는지 확인해봅시다.
뷰의 사각형을 정의하기 위해선 무엇이 필요할까요? 첫번째로 뷰는 어디에 그려져야 할지 위치를 알아야 합니다. 두번째로는 위치로부터 어떤 크기로 그려져야할지를 알아야합니다. 뷰의 프레임(frame)과 바운드(bounds)는 CGRect라는 구조체를 통해서 표현됩니다. CGRect는 사각형의 크기와 위치에 대한 정보를 담고 있습니다. CGRect의 origin프로퍼티는 CGPoint 타입으로 사각형의 시작점을 나타냅니다. CGRect의 size프로퍼티는 CGSize타입으로 사각형의 높이와 너비를 나타냅니다. CGPoint는 좌표를 표현할 수 있는 x와 y를 갖고 있습니다. CGSize은 위치와 높이의 값인 width와 height를 갖고 있습니다.
CGPoint의 x, y와 CGSize의 width, height는 모두 부동소수점 타입인 CGFloat으로 표현됩니다.
생각해보기
뷰의 좌표계에서 프레임과 바운드가 각각 있는 이유는 뭘까요?
어느 상황에서 프레임을 쓰고, 바운드를 쓰면 좋을지 생각해봅시다.
comment
요즘 다시 초심으로 돌아가자는 마인드로 이 강의 시작했는데
단언컨데 다른 강의보다 더 최고입니다. 감사합니다.
코드 리뷰 31일까지인거 막차 타보겠습니다~
잘 모르겠다..
프레임은 (origin, size)고
바운드는 (영역의 좌상단, 우하단 꼭짓점 좌표) 인데,
영역을 따로 제한해서 표시하고 싶을 때는(super view내에) 바운드,
크기를 명시하고 싶은 경우에는 프레임을 쓰지 않을까?
오타가 있는 것 같습니다!
CGSize은 위치와 높이의 값인 width와 height를 갖고 있습니다.
-> CGSize은 너비와 높이의 값인 width와 height를 갖고 있습니다.
프레임을 쓰면 좋은 경우: 한 단계 상위뷰와 비교해서 뷰를 배치하는 경우
바운드를 쓰면 좋은 경우: 스크롤뷰를 사용하는 경우
혹시나 저와 같이 헤메시는분이 있을까하여 알려드립니다. 1-1 에서 인터페이스 빌더로 서브뷰를 만드시고 바로 그 프로젝트 파일에서 1-2의 코딩으로 서브뷰를 만드는 항목을 따라하실 때 '코드로 만든 서브뷰는 보이지 않는 경우' 1-1의 과정 중에서 ViewController를 한번 삭제하고 다시 만들 때 View Controller의 Class가 설정되지 않았기 때문이었습니다. 따라서 이 경우에는 View Controller의 Show in identity Inspector 탭에서 ( Is Initial View Controller를 체크하신 탭의 바로 왼쪽 탭입니다. ) Class를 ViewController로 설정해주시면 정상적으로 작동합니다.
여태 앱만드면서 오토레이아웃을 스토리보드에서만 했었거든요.
코드로 구현도 많이 하나요? 주로 어떤경우에 코드로 오토레이아웃 구현을 하는지 궁금합니다.
진짜.. 너뮤 감사드립니다 ㅠㅠㅠㅠㅠ
영상에서 나오는 3D View(?)의 경우 XCode 10.1 기준 Debug Navigator에 나타나지 않습니다.
에뮬레이터에 실행시킨 이후 좌측 하단 6번째 아이콘인 Debug View Hierarchy 를 누르면 볼 수 있습니다.
코드로 생성한 경우에도 동일한 방법으로 볼 수 있으며, 이후 게이지를 이동시키면 깊이에 대한 분할이 가능합니다.
스토리보드를 사용하지 않고 프로그래밍만으로 뷰를 구성했을 경우 뷰 체제를 쉽게 볼 수 있는 방법이 있을까요?
그냥 단순하게 뷰 파악하기 좋게 코드를 짜야하는 것일까요???