"Create a composite interface by combining content from one or more view controllers with other custom views."
다른 커스텀 뷰를 갖는 하나 혹은 하나 이상의 뷰 컨트롤러로들부터 컨텐트를 결합해 복합 인터페이스를 생성합니다.
컨테이너 뷰 컨트롤러는 컨텐트와 컨텐트를 화면에 표시하는 방법을 분리함으로써 더 나은 캡슐화를 촉진시킵니다. 앱의 데이터를 표시하는 컨텐트 뷰 컨트롤러와 달리 컨테이너 뷰 컨트롤러는 다른 뷰 컨트롤러들을 화면에 정렬하고 뷰 컨트롤러들 사이에 네비게이션을 처리하면서 해당 뷰 컨트롤러들을 보여줍니다.
컨테이너 뷰 컨트롤러 역시 뷰 컨트롤러이기 때문에 컨테이너 뷰 컨트롤러 또한 윈도우에 표시하거나 제시할 수 있습니다. 컨테이너 뷰 컨트롤러는 하나 혹은 하나 이상의 자식 뷰 컨트롤러로부터 뷰들을 뷰 계층구조에 통합시키는 복합 인터페이스를 관리하기도 합니다. 각가의 자식은 스스로의 뷰 계층구조를 관리합니다. 컨테이너는 자식의 루트 뷰의 위치와 크기를 관리합니다.
많은 컨테이너 뷰 컨트롤러가 앱의 컨텐트에 대한 다른 부분들 사이에서 탐색을 용이하도록 합니다. 사용자가 다른 뷰 컨트롤러들 사이를 탐색할 수 있도록 해주는 UINavigationController
, UITabBarController
, UIPageViewController
가 대표적입니다. 가지고 있는 컨텐트를 더 효율적으로 조직화하기 위해서 컨테이너 뷰 컨트롤러를 사용할 수 있습니다. 예를 들어 UISplitViewController
는 아이패드에서 두 뷰 컨트롤러를 양옆으로 표시합니다. 네비게이션과 조직화 사이의 유일한 차이는 네비게이션의 경우 자식 뷰 컨트롤러를 변경시키려면 커스텀 API를 요구한다는 것입니다. 나머지 구현 부분은 동일합니다.
컨테이너 뷰 컨트롤러가 자식 뷰 컨트롤러를 동적으로 변경시키려 한다면, 해당 자식들을 코드 작성으로 추가하는 것이 쉬운 방법입니다. 커스텀 네비게이션 인터페이스는 자식 뷰 컨트롤러를 변경시키는 것을 통해 네비게이션을 용이하게 하고, 인터페이스 설정의 일부분으로써 자식 뷰 컨트롤러를 변경시키게 될 것입니다.
인터페이스에 새 자식 뷰 컨트롤러를 각각 추가하려면 아래 단계를 순서대로 수행하시기 바랍니다.
addChild(_:)
메소드를 호출합니다.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
은 우선 컨테이너 뷰 컨트롤러를 통해 많은 요청들을 라우팅합니다. 이는 모든 자식 뷰 컨트롤러에 대한 동작을 변경시킬 수 있는 기회를 제공합니다. 예를 들어 컨테이너 뷰 컨트롤러는 자식의 특성을 오버라이드함으로써 자식이 특정 모양이나 동작을 채택하도록 합니다.
컨테이너로부터 자식 뷰 컨트롤러를 제거하려면 아래 단계를 순서대로 수행하시기 바랍니다.
willMove(toParent:)
메소드를 nil
값과 함께 호출합니다.removeFromSuperview()
를 호출합니다.removeFromParent()
메소드를 호출합니다.컨테이너-자식 관계를 끊는 것은 UIKit
에게 컨테이너 뷰 컨트롤러가 더 이상 자식의 컨텐트를 표시하지 않는다고 알려줍니다. 자식 뷰 컨트롤러에 대한 다른 레퍼런스 유지를 남겨둘 수도 있습니다. 예를 들어 UINavigationController
는 자식 뷰 컨트롤러의 스택을 관리하지만, 주어진 시간에 오직 하나 혹은 둘의 자식에 컨테이너-자식 관계를 유지합니다.
컨테이너 뷰 컨트롤러가 컨텐트를 조직화하고 해당 컨텐트를 이후에 변경하지 않는다면, 컨테이너 뷰를 사용해 UI를 설정하시기 바랍니다. 컨테이너 뷰는 자식 뷰 컨트롤러의 컨텐트를 나타내는 프록시 뷰입니다. 인터페이스가 추가하게 되면, 보통의 뷰처럼 보이지만 연결된 뷰 컨트롤러를 갖고 있습니다.
인터페이스에서 다른 뷰에서 했던 방법과 마찬가지로 컨테이너 뷰에 대한 크기와 위치를 설정하시기 바랍니다. 기기 및 설정에 따라 달라질 수 있도록 뷰의 크기와 위치를 구체화하는 제약을 추가해야 합니다. 그러나 컨테이너 뷰 자체에 하위뷰를 추가하지 않아야 합니다. 대신 연결된 뷰 컨트롤러의 뷰에 추가해야 합니다.
하나 혹은 하나 이상의 컨테어너 뷰를 포함하는 뷰 컨트롤러를 인스턴스화 하는 경우 UIKit
은 연결된 자식 뷰 컨트롤러 또한 인스턴스화 합니다. 새 뷰 컨트롤러를 생성한 이후 UIKit
은 새 뷰 컨트롤러들을 요청한 기존 뷰 컨트롤러의 자식으로 추가합니다. addChild(_:)
를 호출할 필요는 없습니다.
커스텀 컨테이너 뷰 컨트롤러에서 아래에 보이는 추가적인 동작에 대한 구현을 고려해보시기 바랍니다.
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