Showing and Hiding View Controllers

Panther·2021년 7월 27일
0

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

"Display view controllers using different techniques, and pass data between them during transitions."

다른 테크닉을 사용해서 뷰 컨트롤러를 표시합니다. 그리고 뷰 컨트롤러 사이에 전환이 진행되는 동안 데이터를 전달합니다.

Overview

뷰 컨트롤러를 제시하거나 해제하는 것을 통해 앱의 인터페이스를 변경시킬 수 있습니다. 모든 윈도우는 윈도우에서 초기 컨텐트를 제공하는 루트 뷰 컨트롤러를 가집니다. 새 뷰 컨트롤러를 제시하는 것은 윈도우에 새로운 뷰 집합을 설치함으로써 해당 컨텐트를 변경합니다. 뷰 컨트롤러가 더 이상 필요하지 않을 때, 해당 뷰 컨트롤러를 해제하는 것은 윈도우로부터 뷰 컨트롤러의 뷰를 제거합니다. 아래에 있는 방법 중 한 가지를 통해 뷰 컨트롤러를 제시할 수 있습니다.

  • 스토리보드에서 프리젠테이션을 시각적으로 설정합니다.
  • 컨테이너 뷰 컨트롤러에 뷰 컨트롤러를 끼워 넣습니다.
  • UIViewController의 메소드를 직접 호출합니다.

각각의 테크닉은 프리젠테이션과 해제 프로세스에서 다른 양의 컨트롤을 제공합니다.

Specify Presentations Visually in Your Storyboard File

뷰 컨트롤러를 제시하거나 해제하기 위한 방법으로 스토리보드에서 세그를 사용하는 것을 권장합니다. 세그는 하나의 뷰 컨트롤러에서 다른 뷰 컨트롤러로 전환하는 것을 시각적으로 나타내는 요소입니다. 세그는 초기 뷰 컨트롤러에 있는 버튼 탭 혹은 테이블 행 선택과 같은 액션에서 시작합니다. 해당 액션이 발생하면 UIKit은 세그의 다른 끝에 있는 뷰 컨트롤러를 생성하고 자동으로 이를 제시합니다. 스토리보드에서 세그를 생성하고 설정했기 때문에 이 세그를 매우 빠르게 변경시킬 수도 있습니다.

컨트롤 혹은 제스처 리코그나이저처럼 액션 메소드를 구현할 수 있는 모든 객체로부터 세그가 시작될 수 있습니다. 테이블 행과 컬렉션 뷰 셀로부터 세그를 시작할 수도 있습니다.

  1. 현재 뷰 컨트롤러에 있는 컨트롤 혹은 객체를 우클릭합니다.
  2. 커서를 제시하고자 하는 뷰 컨트롤러에 드래그합니다.
  3. Xcode가 제공하는 리스트 중 원하는 세그의 종류를 선택합니다.

스토리보드는 두 뷰 컨트롤러 사이에서 화살표를 통해 세그를 나타냅니다. 세그를 선택하는 것은 UIKit이 수행하길 원하는 프리젠테이션의 종류를 포함해 세그에 대한 정보를 보여줍니다. 프리젠테이션 타입을 수정하거나 세그 아이덴티파이어와 같은 추가적인 세부사항을 설정할 수 있습니다. Customizing the Behavior of Segue-Based Presentations에서 설명하고 있는 것처럼 런타임에 추가로 세그를 커스터마이징할 수 있습니다.

https://developer.apple.com/documentation/uikit/resource_management/customizing_the_behavior_of_segue-based_presentations
https://velog.io/@panther222128/Customizing-the-Behavior-of-Segue-Based-Presentations

스토리보드에서 뷰 컨트롤러를 해제하는 방법은 Dismissing a View Controller with an Unwind Segue를 살펴보시기 바랍니다.

https://developer.apple.com/documentation/uikit/resource_management/dismissing_a_view_controller_with_an_unwind_segue
https://velog.io/@panther222128/Dismissing-a-View-Controller-with-an-Unwind-Segue

Let the Current Context Define the Presentation Technique

여러 위치에서 같은 뷰 컨트롤러를 재사용하는 것은 잠재적인 문제를 발생시킵니다. 현재 컨텍스트에 기반해 다른 방법으로 제시하는 것이 문제가 될 수 있습니다. 예를 들어 네비게이션 컨트롤러에 끼워 넣으려고 하면서도 다른 곳에서 모달로 제시하길 원할 수 있습니다. UIKit은 이 문제를 UIViewControllershow(:sender:), showDetailViewController(:sender:) 메소드와 함께 문제를 해결합니다. 이 메소드들은 현재 컨텍스트에서 가장 적합한 방법으로 뷰 컨트롤러를 제시합니다.

show(:sender:), showDetailViewController(:sender:) 메소드를 호출하는 경우 UIKit은 프리젠테이션을 위해 가장 적합한 컨텍스트를 결정합니다. 구체적으로 상응하는 show 메소드를 구현하고 있는 뷰 컨트롤러를 찾기 위해 targetViewController(forAction:sender:) 메소드를 호출합니다. 만약 부모가 해당 메소드를 구현하고 있고 프리젠테이션을 처리하길 원한다면, UIKit은 부모의 구현사항을 호출합니다. UINavigationController 객체의 show(_:sender:) 메소드는 새 뷰 컨트롤러를 네비게이션 스택에 추가합니다. 만약 뷰 컨트롤러가 프리젠테이션을 처리하지 않는다면, UIKit은 뷰 컨트롤러를 모달로 제시합니다.

아래 코드 예시는 뷰 컨트롤러를 생성하고 있고, show(_:sender:) 메소드 사용을 보여줍니다. Show 종류의 세그를 생성하는 것과 동일한 코드가 됩니다.

    @IBAction func showSecondViewController() {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let secondVC = storyboard.instantiateViewController(identifier: "SecondViewController")

        show(secondVC, sender: self)
    }

뷰 컨트롤러가 보인 이후 뷰 컨트롤러를 해제하는 방법을 결정하기 위해 현제 컨텍스트를 사용해야 합니다. dismiss(animated:completion:) 메소드를 호출하는 것이 항상 가장 적합한 옵션이 되는 것인 아닐 수 있습니다. 예를 들어 네비게이션이 네비게이션 스택에 뷰 컨트롤러를 추가했을 경우 이 메소드를 호출하지 않아야 합니다. 대신 현재 컨텍스트를 결정하는 것과 응답에 적합한 액션을 취할 수 있도록 presentingViewController, splitViewController, navigationController, tabBarController의 속성을 사용해야 합니다. 이 응답은 UI를 해제하기 위해 완료 버튼이나 기타 컨트롤을 숨기기 위해 뷰 컨트롤러의 UI 수정을 포함합니다.

Note
커스텀 컨테이너 뷰 컨트롤러르 구현하는 경우 프리젠테이션을 처리하기 위해 show(:sender:), showDetailViewController(:sender:) 메소드를 구현하시기 바랍니다. 더 많은 정보는 reating a Custom Container View Controller를 살펴보시기 바랍니다.

https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller
https://velog.io/@panther222128/Creating-a-Custom-Container-View-Controller

Embed a View Controller Inside a Container View Controller

컨테이너 뷰 컨트롤러는 하나 혹은 하나 이상의 자식 뷰 컨트롤러로부터 컨텐트를 끼워넣고, 결합된 인터페이스를 화면에 제시합니다. 자식 뷰 컨트롤러를 끼워넣는 것은 container-specific 접근방식을 사용해 자식 뷰 컨트롤러를 제시합니다. 예를 들어 네비게이션 컨트롤러는 초기에 자식 뷰 컨트롤러를 화면에 보여주지 않고, 이후 애니메이션을 통해 스크린에 위치시킵니다.

표준 UIKit 컨테이너 뷰 컨트롤러는 뷰 컨트롤러를 자식으로써 끼워넣기 위해 세그, show(:sender:), showDetailViewController(:sender:) 메소드와 함께 작동합니다. 코드 작성으로 자식 뷰 컨트롤러를 추가하거나 제거하기 위한 추가적인 API를 정의하기도 합니다. 대부분의 전환을 처리하기 위해 세그와 show 메소드를 사용하시기 바랍니다. 앱의 UI를 이전 상태로 저장하는 경우를 포함해 아래 테이블에 있는 메소드를 사용해서 뷰 컨트롤러의 설정을 수행하시기 바랍니다.

ContainerPresentation options
UISplitViewControllerviewControllers 속성을 사용해 두 초기 뷰 컨트롤러를 교체합니다. 첫 번째(primary) 뷰 컨트롤러는 leading pane에 나타나고 두 번째(detail) 뷰 컨트롤러는 trailing pane에 나타납니다.
UINavigationControllerviewControllers 속성을 사용해 네비게이션 스택의 컨텐츠를 교체합니다. setViewControllers(_:animated:) 메소드를 사용해 뷰 컨트롤러의 하위집합을 동시에 추가하거나 삭제합니다.
UITabBarControllerviewControllers 속성을 사용해 초기 탭을 교체합니다. setViewControllers(_:animated:) 메소드를 사용해 동적으로 현재 탭을 변경할 수 있습니다.
UIPageViewControllerUIPageViewControllerDataSource 객체를 사용해 모든 자식 뷰 컨트롤러를 제공합니다.

제시된 뷰 컨트롤러를 제거하거나 교체하려면 항상 컨테이너 뷰 컨트롤러의 API를 사용하시기 바랍니다.

Present a View Controller Modally

사용자에게 중요 정보를 알리는 것과 같은 앱의 작동 흐름상 일시적인 인터럽션을 생성하려면 모달 프리젠테이션을 사용하시기 바랍니다. 모달 프리젠테이션은 현재 뷰 컨트롤러를 전체 혹은 일부분만을 덮습니다. 사용하는 프리젠테이션 스타일에 따라 달라집니다. 전체 스크린 프리젠테이션은 항상 이전 컨텐트를 교체합니다. 시트 스타일 프리젠테이션은 기존 컨텐트의 일부분을 여전히 보이도록 할 것입니다. 각 프리젠테이션 스타일의 실제 모습은 현재 특선 환경에 따라 달라집니다.

모달 프리젠테이션을 설정하려면 새 뷰 컨트롤러를 생성하고 present(_:animated:completion:) 메소드를 호출하시기 바랍니다. 이 메소드는 UIModalPresentationStyle.automatic 스타일과 UIModalTransitionStyle.coverVertical 전환 애니메이션을 사용해 목표 위치에 새 뷰 컨트롤러를 애니메이션으로 이동시킵니다. 스타일을 변경하려면 제시한 뷰 컨트롤러의 modalPresentationStyle, modalTransitionStyle 속성을 수정하시기 바랍니다. 아래 코드 예시는 cross-dissolve 애니메이션을 사용해 전체 스크린 프리젠테이션을 생성하고자 모든 스타일을 변경시킨 예시입니다.

    @IBAction func presentSecondViewController() {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let secondVC = storyboard.instantiateViewController(identifier: "SecondViewController")
        
        secondVC.modalPresentationStyle = .fullScreen
        secondVC.modalTransitionStyle = .crossDissolve
        
        present(secondVC, animated: true, completion: nil)
    }

모달을 통해 제시된 뷰 컨트롤러를 해제하려면 뷰 컨트롤러의 dismiss(animated:completion:) 메소드를 호출하시기 바랍니다.

0개의 댓글