Creating a Custom Container View Controller

Panther·2021년 7월 27일
0

https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller

"Create a composite interface by combining content from one or more view controllers with other custom views."

다른 커스텀 뷰를 갖는 하나 혹은 하나 이상의 뷰 컨트롤러로들부터 컨텐트를 결합해 복합 인터페이스를 생성합니다.

Overview

컨테이너 뷰 컨트롤러는 컨텐트와 컨텐트를 화면에 표시하는 방법을 분리함으로써 더 나은 캡슐화를 촉진시킵니다. 앱의 데이터를 표시하는 컨텐트 뷰 컨트롤러와 달리 컨테이너 뷰 컨트롤러는 다른 뷰 컨트롤러들을 화면에 정렬하고 뷰 컨트롤러들 사이에 네비게이션을 처리하면서 해당 뷰 컨트롤러들을 보여줍니다.

컨테이너 뷰 컨트롤러 역시 뷰 컨트롤러이기 때문에 컨테이너 뷰 컨트롤러 또한 윈도우에 표시하거나 제시할 수 있습니다. 컨테이너 뷰 컨트롤러는 하나 혹은 하나 이상의 자식 뷰 컨트롤러로부터 뷰들을 뷰 계층구조에 통합시키는 복합 인터페이스를 관리하기도 합니다. 각가의 자식은 스스로의 뷰 계층구조를 관리합니다. 컨테이너는 자식의 루트 뷰의 위치와 크기를 관리합니다.

많은 컨테이너 뷰 컨트롤러가 앱의 컨텐트에 대한 다른 부분들 사이에서 탐색을 용이하도록 합니다. 사용자가 다른 뷰 컨트롤러들 사이를 탐색할 수 있도록 해주는 UINavigationController, UITabBarController, UIPageViewController가 대표적입니다. 가지고 있는 컨텐트를 더 효율적으로 조직화하기 위해서 컨테이너 뷰 컨트롤러를 사용할 수 있습니다. 예를 들어 UISplitViewController는 아이패드에서 두 뷰 컨트롤러를 양옆으로 표시합니다. 네비게이션과 조직화 사이의 유일한 차이는 네비게이션의 경우 자식 뷰 컨트롤러를 변경시키려면 커스텀 API를 요구한다는 것입니다. 나머지 구현 부분은 동일합니다.

Add a Child View Controller Programmatically to Your Content

컨테이너 뷰 컨트롤러가 자식 뷰 컨트롤러를 동적으로 변경시키려 한다면, 해당 자식들을 코드 작성으로 추가하는 것이 쉬운 방법입니다. 커스텀 네비게이션 인터페이스는 자식 뷰 컨트롤러를 변경시키는 것을 통해 네비게이션을 용이하게 하고, 인터페이스 설정의 일부분으로써 자식 뷰 컨트롤러를 변경시키게 될 것입니다.

인터페이스에 새 자식 뷰 컨트롤러를 각각 추가하려면 아래 단계를 순서대로 수행하시기 바랍니다.

  1. 포함 관계를 설정하기 위해 컨테이너 뷰 컨트롤러의 addChild(_:) 메소드를 호출합니다.
  2. 컨테이너의 뷰 계층구조에 자식의 루트 뷰를 추가합니다.
  3. 자식의 루트 뷰 크기와 위치를 설정하기 위해 제약을 추가합니다.
  4. 전환이 완료되었다는 것을 알릴 수 있도록 자식 뷰 컨트롤러의 didMove(toParent:) 메소드를 호출합니다.

아래 예시 코드는 스토리보드로부터 새 자식 뷰 컨트롤러를 인스턴스화하고, 현재 뷰 컨트롤러의 자식으로써 끼워넣습니다. addChild(_:)를 호출한 이후 코드는 자식의 뷰를 뷰 계층구조에 추가합니다. 그리고 크기와 위치를 위한 레이아웃 제약을 설정합니다. 프로세스의 마지막에 자식의 상태를 알려줍니다.

// Create a child view controller and add it to the current view controller.
let storyboard = UIStoryboard(name: "Main", bundle: .main)
if let viewController = storyboard.instantiateViewController(identifier: "imageViewController")
                                    as? ImageViewController {
   // Add the view controller to the container.
   addChild(viewController)
   view.addSubview(viewController.view)
            
   // Create and activate the constraints for the child’s view.
   onscreenConstraints = configureConstraintsForContainedView(containedView: viewController.view,
                             stage: .onscreen)
   NSLayoutConstraint.activate(onscreenConstraints)
     
   // Notify the child view controller that the move is complete.       
   viewController.didMove(toParent: self)
}

뷰 컨트롤러 사이에 컨테이너-자식 관계를 형성하는 것은 UIKit이 의도치 않게 인터페이스를 방해하는 것을 방지합니다. UIKit은 보통 앱의 뷰 컨트롤러 각각에 정보를 라우팅합니다. 컨테이너-자식 관계가 존재하는경우 UIKit은 우선 컨테이너 뷰 컨트롤러를 통해 많은 요청들을 라우팅합니다. 이는 모든 자식 뷰 컨트롤러에 대한 동작을 변경시킬 수 있는 기회를 제공합니다. 예를 들어 컨테이너 뷰 컨트롤러는 자식의 특성을 오버라이드함으로써 자식이 특정 모양이나 동작을 채택하도록 합니다.

Remove a Child View Controller from Your Content

컨테이너로부터 자식 뷰 컨트롤러를 제거하려면 아래 단계를 순서대로 수행하시기 바랍니다.

  1. willMove(toParent:) 메소드를 nil 값과 함께 호출합니다.
  2. 자식의 루트 뷰에 대한 모든 제약을 비활성화하거나 제거합니다.
  3. 뷰 계층구조로부터 자식을 제거하기 위해 자식의 루트 뷰에 대해서 removeFromSuperview()를 호출합니다.
  4. 컨테이너-자식 관계의 끝을 마무리하기 위해 자식의 removeFromParent() 메소드를 호출합니다.

컨테이너-자식 관계를 끊는 것은 UIKit에게 컨테이너 뷰 컨트롤러가 더 이상 자식의 컨텐트를 표시하지 않는다고 알려줍니다. 자식 뷰 컨트롤러에 대한 다른 레퍼런스 유지를 남겨둘 수도 있습니다. 예를 들어 UINavigationController는 자식 뷰 컨트롤러의 스택을 관리하지만, 주어진 시간에 오직 하나 혹은 둘의 자식에 컨테이너-자식 관계를 유지합니다.

Embed a Child View Controller in Your Storyboard UI

컨테이너 뷰 컨트롤러가 컨텐트를 조직화하고 해당 컨텐트를 이후에 변경하지 않는다면, 컨테이너 뷰를 사용해 UI를 설정하시기 바랍니다. 컨테이너 뷰는 자식 뷰 컨트롤러의 컨텐트를 나타내는 프록시 뷰입니다. 인터페이스가 추가하게 되면, 보통의 뷰처럼 보이지만 연결된 뷰 컨트롤러를 갖고 있습니다.

인터페이스에서 다른 뷰에서 했던 방법과 마찬가지로 컨테이너 뷰에 대한 크기와 위치를 설정하시기 바랍니다. 기기 및 설정에 따라 달라질 수 있도록 뷰의 크기와 위치를 구체화하는 제약을 추가해야 합니다. 그러나 컨테이너 뷰 자체에 하위뷰를 추가하지 않아야 합니다. 대신 연결된 뷰 컨트롤러의 뷰에 추가해야 합니다.

하나 혹은 하나 이상의 컨테어너 뷰를 포함하는 뷰 컨트롤러를 인스턴스화 하는 경우 UIKit은 연결된 자식 뷰 컨트롤러 또한 인스턴스화 합니다. 새 뷰 컨트롤러를 생성한 이후 UIKit은 새 뷰 컨트롤러들을 요청한 기존 뷰 컨트롤러의 자식으로 추가합니다. addChild(_:)를 호출할 필요는 없습니다.

Support Additional Container Behaviors

커스텀 컨테이너 뷰 컨트롤러에서 아래에 보이는 추가적인 동작에 대한 구현을 고려해보시기 바랍니다.

  • show(_:sender:)를 오버라이드하고, 새 자식 뷰 컨트롤러를 제시하기 위해 이를 사용합니다.
  • 필요한 경우 showDetailViewController(_:sender:) 오버라이드해서 두 번째 자식 뷰 컨트롤러를 제시할 수 있도록 합니다.
  • 자식의 컨텐트를 모호하게 하는 데코레이션 뷰를 고려하기 위해 additionalSafeAreaInsets를 업데이트합니다.
  • 자식 뷰 컨트롤러의 특성을 변경시키기 위해 setOverrideTraitCollection(_:forChild:)를 호출합니다. 예를 들어 자식 뷰 컨트롤러를 항상 수평 혹은 수직 compact로 지정할 수 있습니다.
  • 자식 뷰 컨트롤러가 시스템 제스처에 대한 동작을 결정할 수 있도록 childForScreenEdgesDeferringSystemGestures, childForHomeIndicatorAutoHidden를 오버라이드합니다.
  • 언와인드 세그 액션의 목표인 자식 뷰 컨트롤러의 집합을 제한하기 위해 allowedChildrenForUnwinding(from:)를 오버라이드합니다.

더 많은 정보는 UIViewController에 있는 설명을 보시기 바랍니다.

UIViewController
https://developer.apple.com/documentation/uikit/uiviewcontroller
https://velog.io/@panther222128/ViewController

0개의 댓글