[번역] View Controller Programming Guide for iOS - Presentations and Transitions - Presenting a View Controller

Presenting a View Controller

원문

미리 요약

  • Presenting View Controller는 Presented View Controller를 show하는 뷰 컨트롤러다.
  • Presented View Controller는 Presenting View Controller가 show하는 뷰 컨트롤러다.
  • show 관련 메소드는 컨텍스트에 알맞게 뷰 컨트롤러를 프레젠트한다.
  • present 관련 메소드는 항상 모달로 뷰 컨트롤러를 프레젠트한다.
  • 팝오버를 프레젠트하고 싶다면 추가 구성을 해줄 필요가 있다.
  • UIPresentationController를 서브클래싱하여 프레젠테이션 스타일을 커스터마이징할 수 있다.
  • UIViewControllerTransitioningDelegateUIViewControllerAnimatedTransitioning 등을 사용하여 트랜지션을 커스터마이징할 수 있다.
  • 항상 Presented View Controller를 dismiss하기 위해 Presented View Controller에서 dismiss 메소드를 호출했는데, 문서에서는 Presenting View Controller에서 dismiss 메소드를 호출하는 것을 먼저 언급하고 있다. Presented View Controller에서 dismiss 메소드를 호출해도 그 요청이 Presenting View Controller로 넘어가므로, 화면에 나타난 뷰 컨트롤러의 show 및 dismiss 관리는 모두 Presenting View Controller가 담당하게 되는 것이다.

뷰 컨트롤러를 화면에 표시하는 방법은 두 가지다. 뷰 컨트롤러를 컨테이너 뷰 컨트롤러에 임베드하거나, 뷰 컨트롤러를 프레젠트하는 것이다. 컨테이너 뷰 컨트롤러는 앱의 주요 내비게이션을 제공하나, 프레젠트하는 뷰 컨트롤러들 또한 중요한 내비게이션 도구다. 현재 프레젠트하는 뷰 컨트롤러의 상단에 새로운 뷰 컨트롤러를 표시하기 위해 직접적인 프레젠테이션을 사용할 수 있다. 일반적으로 모달 인터페이스를 구현하고 싶을 때 뷰 컨트롤러를 프레젠트하나, 다른 목적으로도 사용할 수 있다.

뷰 컨트롤러를 프레젠트하는 것에 대한 지원은 UIViewController 클래스에 내장되어 있으며 모든 뷰 컨트롤러 객체에서 사용 가능하다. 어떠한 뷰 컨트롤러라도 다른 어떠한 뷰 컨트롤러에서 프레젠트할 수 있다. UIKit이 다른 뷰 컨트롤러로 그 요청을 리라우팅할 수도 있지만 말이다. 뷰 컨트롤러를 프레젠트하는 것은 프레젠트하는 컨트롤러(presenting view controller)라고 알려진 기존의 뷰 컨트롤러와, 프레젠트되는 컨트롤러(presented view controller)라고 알려진 표시될 새로운 뷰 컨트롤러 간의 관계를 만드는 것이다. 이 관계는 뷰 컨트롤러 계층의 일부를 형성하고 프레젠트되는 뷰 컨트롤러가 디스미스될 때까지 제 자리를 지킨다.

The Presentation and Transition Process

뷰 컨트롤러를 프레젠트하는 것은 새로운 컨텐츠를 화면에 나타내며 애니메이션 효과를 줄 수 있는 빠르고 쉬운 방법이다. UIKit에 내장된 프레젠테이션 매커니즘은 내장 애니메이션이나 커스텀 애니메이션을 사용하여 새로운 뷰 컨트롤러를 표시할 수 있게 해준다. 내장 프레젠테이션 및 애니메이션은 매우 적은 코드를 필요로 한다. UIKit이 모든 작업을 처리하기 때문이다. 또한 매우 적은 노력을 더하여 커스텀 프레젠테이션과 애니메이션을 만들 수도 있다.

코드 또는 세그를 사용하여 뷰 컨트롤러의 프레젠테이션을 개시할 수 있다. 설계 시점에 앱의 내비게이션을 알고 있다면 세그는 프레젠테이션을 개시하는 가장 쉬운 방법이다. 더욱 다이나믹한 인터페이스를 위해, 또는 세그를 개시하기 위한 제어가 없다면, 뷰 컨트롤러를 프레젠트하기 위해 UIViewController의 메소드들을 사용하라.

Presentation Styles

뷰 컨트롤러의 프레젠테이션 스타일은 화면 상에서의 겉모습을 관리한다. UIKit은 많은 표준 프레젠테이션 스타일을 정의하며, 각각은 특정 겉모습과 의도를 가지고 있다. 또한 커스텀 프레젠테이션 스타일도 정의할 수 있다. 앱을 디자인할 때 하려는 것과 가장 알맞는 프레젠테이션 스타일을 선택하고, 적절한 상수를 프레젠트하기 원하는 뷰 컨트롤러의 modalPresentationStyle 프로퍼티에 할당하라.

Full-Screen Presentation Styles

풀 스크린 프레젠테이션 스타일은 전체 화면을 커버하며, 밑에 깔린 컨텐츠와의 인터랙션을 방지한다. 수평 레귤러 환경에서는 오직 풀스크린 스타일만이 완전하게 밑에 깔린 컨텐츠를 커버한다. 나머지 것들은 밑에 깔린 뷰 컨트롤러의 일부분이 통과하여 보여질 수 있도록 흐릿한 뷰나 불투명도를 만든다. 수평 컴팩트 환경에서 풀스크린 프레젠테이션은 자동으로 UIModalPresentationStyle.fullScreen 스타일을 채택하며 밑에 깔린 컨텐츠 전체를 커버한다.

알아두기 : UIModalPresentationStyle.fullScreen 스타일을 사용하여 뷰 컨트롤러를 프레젠트할 때, UIKit은 일반적으로 트랜지션 애니메이션이 끝난 후 밑에 깔린 뷰 컨트롤러의 뷰를 제거한다. UIModalPresentationStyle.overFullScreen 스타일을 대신 지정하여 그러한 뷰들이 제거되지 않도록 할 수 있다. 프레젠트되는 뷰 컨트롤러가 투명한 영역을 가지고 있어 밑에 깔린 컨텐츠가 이를 통하여 보여질 수 있도록 하기 위해서도 이 스타일을 사용할 수 있다.

풀스크린 프레젠테이션 스타일들 중 하나를 사용할 때, 프레젠테이션을 개시하는 뷰 컨트롤러는 반드시 그 자체의 전체 화면을 커버해야 한다. 프레젠트하는 뷰 컨트롤러가 화면을 커버하지 않는다면, UIKit은 그러한 것을 찾을 때까지 뷰 컨트롤러 계층을 타고 내려갈 것이다. 화면을 채우는 중간 뷰 컨트롤러를 찾지 못했다면, UIKit은 윈도우의 루트 뷰 컨트롤러를 사용한다.

The Popover Style

UIModalPresentationStyle.popover 스타일은 뷰 컨트롤러를 팝오버 뷰 안에 표시한다. 팝오버는 포커스를 받거나 선택된 객체와 관련된 추가 정보나 아이템 리스트를 표시하는 데 유용하다. 수평 레귤러 환경에서 팝오버 뷰는 화면의 일부분만을 커버한다. 수평 컴팩트 환경에서 팝오버는 UIModalPresentationStyle.overFullScreen 프레젠테이션 스타일을 기본적으로 채택한다. 팝오버 뷰 바깥에서의 탭은 자동으로 팝오버를 디스미스한다.

수평 컴팩트 환경에서 팝오버는 풀스크린 프레젠테이션을 채택하기 때문에, 일반적으로 이 채택을 처리하기 위해 팝오버 코드를 수정할 필요가 있다. 풀스크린 모드에서 프레젠트되는 팝오버를 디스미스할 방법이 필요하다. 버튼을 추가하거나, 팝오버를 디스미스 가능한 컨테이너 뷰 컨트롤러에 임베드하거나, 그 자체의 채택 동작을 변경하여 처리할 수 있다.

The Current Context Styles

UIModalPresentationStyle.currentContext 스타일은 인터페이스의 특정 뷰 컨트롤러를 커버한다. 컨텍스트 관련 스타일을 사용할 때, definesPresentationContext 프로퍼티를 true로 설정하여 커버하기 원하는 뷰 컨트롤러가 무엇인지 지정한다.

알아두기 : UIModalPresentationStyle.fullScreen 스타일을 사용하여 뷰 컨트롤러를 프레젠트할 때, UIKIt은 일반적으로 트랜지션 애니메이션이 끝난 후 밑에 깔린 뷰 컨트롤러의 뷰를 제거한다. 대신 UIModalPresentationStyle.overCurrentContext를 지정하여 그러한 뷰가 제거되는 것을 막을 수 있다. 프레젠트되는 뷰 컨트롤러가 투명한 영역을 가지고 있어 밑에 깔린 영역이 이를 통해 보일 수 있을 때 이 스타일을 사용할 수 있다.

프레젠테이션 컨텍스트를 정의한 뷰 컨트롤러는 또한 프레젠테이션 동안 사용할 트랜지션 애니메이션도 정의할 수 있다. 일반적으로 UIKit은 프레젠트되는 뷰 컨트롤러의 modalTransitionStyle 프로퍼티에 있는 값을 사용하여 화면에 나타나는 뷰 컨트롤러에 애니메이션 효과를 준다. 프레젠트하는 컨텍스트 뷰 컨트롤러가 providesPresentationContextTransitionStyletrue로 설정했다면, UIKit은 대신 그 뷰 컨트롤러의 modalTransitionStyle 프로퍼티의 값을 사용한다.

수평 컴팩트 환경에서 트랜지션이 일어날 때, 현재 컨텍스트 스타일은 UIModalPresentationStyle.fullScreen 스타일을 채택한다. 이 동작을 변경하려면 다른 프레젠테이션 스타일이나 뷰 컨트롤러를 지정하기 위해 어댑티브 프레젠테이션 델리게이트를 사용하라.

Custom Presentation Styles

UIModalPresentationStyle.custom 스타일은 커스텀 스타일을 사용하여 뷰 컨트롤러를 프레젠트할 수 있도록 해준다. 커스텀 스타일을 만드는 것은 UIPresentationController를 서브클래싱하여 화면 상에 나타나는 커스텀 뷰에 애니메이션 효과를 주고 프레젠트되는 뷰 컨트롤러의 크기와 위치를 설정하기 위해 그 메소드들을 사용하는 것을 포함한다. 프레젠테이션 컨트롤러는 또한 프레젠트되는 뷰 컨트롤러의 특성 변화에 의해 발생하는 적응 또한 처리한다.

Creating Custom Presentations에서 커스텀 프레젠테이션 컨트롤러를 정의하는 방법에 대해 확인하라.

Transition Styles

트랜지션 스타일은 프레젠트되는 뷰 컨트롤러를 표시하기 위해 사용되는 애니메이션의 타입을 결정한다. 내장 트랜지션 스타일을 위해 프레젠트하기 원하는 뷰 컨트롤러의 modalTransitionStyle 프로퍼티에 표준 트랜지션 스타일 중 하나를 할당한다. 뷰 컨트롤러를 프레젠트할 때 UIKit은 그 스타일에 부합하는 애니메이션을 만든다. 예를 들어 UIModalTransitionStyle.coverVertical은 뷰 컨트롤러가 화면에 나타날 때 표준 슬라이드업 트랜지션 애니메이션을 나타낸다. 뷰 컨트롤러 B는 화면 밖에서 시작하여 뷰 컨트롤러 A를 덮으며 상단으로 애니메이션과 함께 올라간다. 뷰 컨트롤러 B가 디스미스될 때 애니메이션은 거꾸로 되어 뷰 컨트롤러 B가 뷰 컨트롤러 A를 드러내게 하며 슬라이드다운된다.

애니메이터 객체와 트랜지셔닝 델리게이트를 사용하여 커스텀 트랜지션을 만들 수 있다. 애니메이터 객체는 뷰 컨트롤러를 화면에 두기 위한 트랜지션 애니메이션을 만든다. 트랜지셔닝 델리게이트는 적절한 때에 UIKit에게 애니메이터 객체를 제공한다. Customizing the Transition Animations에서 커스텀 트랜지션을 구현하기 위한 방법을 확인하라.

Presenting Versus Showing a View Controller

UIViewController 클래스는 뷰 컨트롤러를 표시하기 위한 두 가지 방법을 제공한다.

  • show(_:sender:)showDetailViewController(_:sender:) 메소드는 뷰 컨트롤러를 표시하기 위한 가장 어댑티브하고 유연한 방법을 제공한다. 이 메소드들은 뷰 컨트롤러가 프레젠테이션을 처리하는 최상의 방법을 결정할 수 있게 해준다. 예를 들어, 컨테이너 뷰 컨트롤러는 뷰 컨트롤러를 모달로 프레젠트하는 대신 자식으로 통합하고 싶을 수 있다. 기본 동작은 뷰 컨트롤러를 모달로 프레젠트한다.
  • present(_:animated:completion:) 메소드는 항상 뷰 컨트롤러를 모달로 표시한다. 이 메소드를 호출한 뷰 컨트롤러는 궁극적으로 프레젠테이션을 처리하지 않을 수 있더라도, 프레젠테이션은 항상 모달이다. 이 메소드는 수평 컴팩트 환경을 위해 프레젠테이션 스타일을 조정한다.
  • show(_:sender:)showDetailViewController(_:sender:) 메소드는 프레젠테이션을 개시하기 위해 선호되는 방법이다. 뷰 컨트롤러는 나머지 뷰 컨트롤러 계층이나 현재 뷰 컨트롤러의 계층에서의 위치에 대해 알지 못하고 메소드를 호출할 수 있다. 이 메소드들은 또한 조건절을 작성하지 않고도 앱의 다른 부분에서 뷰 컨트롤러를 재사용하기 더 쉽게 해준다.

Presenting a View Controller

뷰 컨트롤러의 프레젠테이션을 개시하기 위한 몇 가지 방법이 있다.

  • 자동으로 뷰 컨트롤러를 프레젠트하기 위해 세그를 사용한다. 세그는 인터페이스 빌더에서 지정한 정보를 사용하여 뷰 컨트롤러를 초기화하고 프레젠트한다. Using Segues에서 세그를 구성하는 방법에 대해 더 확인하라.
  • show(_:sender:)showDetailViewController(_:sender:) 메소드를 사용하여 뷰 컨트롤러를 표시한다. 커스텀 뷰 컨트롤러에서 더욱 잘 들어맞도록 이 메소드들의 동작을 변경할 수 있다.
  • present(_:animated:completion:) 메소드를 호출하여 뷰 컨트롤러를 모달로 프레젠트한다.

Dismissing a Presented View Controller에서 이 테크닉 중 하나를 사용하여 프레젠트된 뷰 컨트롤러를 디스미스하는 방법에 대해 확인하라.

Showing View Controllers

show(_:sender:)showDetailViewController(_:sender:) 메소드를 사용할 때, 화면에 뜰 새로운 뷰 컨트롤러를 구하는 프로세스는 직관적이다.

  1. 프레젠트하기 원하는 뷰 컨트롤러 객체를 만든다. 뷰 컨트롤러를 만들 때, 작업을 수행하기 위해 필요로 하는 데이터가 있다면 그것과 함께 초기화하는 것은 당신의 책임이다.
  2. 새로운 뷰 컨트롤러의 modalPresentationStyle 프로퍼티를 선호하는 프레젠테이션 스타일로 설정한다. 이 스타일은 최종 프레젠테이션에서 사용되지 않을 수 있다.
  3. 새로운 뷰 컨트롤러의 modalTransitionStyle 프로퍼티를 선호하는 트랜지션 애니메이션 스타일로 설정한다. 이 스타일은 최종 프레젠테이션에서 사용되지 않을 수 있다.
  4. 현재 뷰 컨트롤러의 show(_:sender:)showDetailViewController(_:sender:) 메소드를 호출한다.

UIKit은 show(_:sender:)showDetailViewController(_:sender:) 메소드의 호출을 적절한 프레젠트하는 뷰 컨트롤러로 보낸다. 그러면 뷰 컨트롤러는 프레젠테이션을 수행하기 위한 최상의 방법을 결정할 수 있고, 필요하다면 프레젠테이션 스타일과 트랜지션 스타일을 변경할 수 있다. 예를 들어 내비게이션 컨트롤러는 내비게이션 스택에 뷰 컨트롤러를 푸시할 것이다.

Presenting Versus Showing a View Controller에서 뷰 컨트롤러를 쇼하는 것과 모달로 프레젠트하는 것 간의 차이에 대해 확인하라.

Presenting View Controllers Modally

뷰 컨트롤러를 직접 프레젠트할 때, 새로운 뷰 컨트롤러는 어떻게 표시될 것이며, 화면에 뜰 때 애니메이션 효과를 내야 하는지 UIKit에게 알린다.

  1. 프레젠트하기 원하는 뷰 컨트롤러 객체를 만든다. 뷰 컨트롤러를 만들 때, 작업을 수행하기 위해 필요로 하는 데이터가 있다면 그것과 함께 초기화하는 것은 당신의 책임이다.
  2. 새로운 뷰 컨트롤러의 modalPresentationStyle 프로퍼티를 바라는 프레젠테이션 스타일로 설정한다.
  3. 새로운 뷰 컨트롤러의 modalTransitionStyle 프로퍼티를 바라는 애니메이션 스타일로 설정한다.
  4. 현재 뷰 컨트롤러의 present(_:animated:completion:) 메소드를 호출한다.

present(_:animated:completion:) 메소드를 호출하는 뷰 컨트롤러는 실제로 모달 프레젠테이션을 수행하는 것이 아닐 수도 있다. 프레젠테이션 스타일은 뷰 컨트롤러가 프레젠트되어야 하는 방법을 결정하며, 이는 프레젠트하는 뷰 컨트롤러가 요구하는 특성을 포함한다. 예를 들어 풀스크린 프레젠테이션은 반드시 풀스크린 뷰 컨트롤러로부터 개시되어야 한다. 현재 프레젠트하는 뷰 컨트롤러가 적합하지 않다면, UIKit은 적합한 것을 찾을 때까지 뷰 컨트롤러 계층을 따라 내려간다. 모달 프레젠테이션의 완료에서 UIKit은 영향을 받는 뷰 컨트롤러들의 presentingViewControllerpresentedViewController 프로퍼티를 갱신한다.

Presenting a View Controller in a Popover

팝오버는 프레젠트하기 이전에 추가적인 구성을 필요로 한다. 모달 프레젠테이션 스타일을 UIModalPresentationStyle.popover로 설정한 후, 다음의 팝오버와 관련된 특성을 구성하라.

  • 뷰 컨트롤러의 preferredContentSize 프로퍼티를 바라는 크기로 설정한다.
  • 연관된 UIPopoverPresentationController 객체를 사용하여 팝오버의 앵커 포인트를 설정한다. 이는 뷰 컨트롤러의 popoverPresentationController 프로퍼티로 접근 가능하다. 다음의 것들 중 오직 하나만 설정하라.
    • barButtonItem 프로퍼티에 바 버튼 아이템을 설정한다.
    • sourceViewsourceRect 프로퍼티를 뷰 중 하나의 특정 영역으로 설정한다.

필요하다면 팝오버의 겉모습에 대해 다른 조절을 하기 위해 UIPopoverPresentationController 객체를 사용할 수 있다. 팝오버 프레젠테이션 컨트롤러는 프레젠테이션 프로세스 동안의 변화에 응답하기 위해 사용할 수 있는 델리게이트 객체도 지원한다. 예를 들어 팝오버가 나타나고, 사라지고, 화면에서 위치를 재설정할 때 응답할 수 있는 델리게이트를 사용할 수 있다. UIPopoverPresentationController 클래스 레퍼런스에서 이 객체에 대해 더 확인하라.

Dismissing a Presented View Controller

프레젠트된 뷰 컨트롤러를 디스미스하기 위해 프레젠트하는 뷰 컨트롤러의 dismiss(animated:completion:) 메소드를 호출하라. 프레젠트되는 뷰 컨트롤러 자체에서도 이 메소드를 호출할 수 있다. 프레젠트되는 뷰 컨트롤러에서 메소드를 호출할 때, UIKit은 자동으로 요청을 프레젠트하는 뷰 컨트롤러로 전달한다.

뷰 컨트롤러가 디스미스되기 전에 항상 중요한 정보를 저장하라. 뷰 컨트롤러를 디스미스하면 뷰 컨트롤러 계층에서 제거되고 뷰를 화면에서 제거한다. 다른 곳에서 뷰 컨트롤러를 강하게 참조하지 않는다면 디스미스하는 것은 관련된 메모리의 해제도 함께 불러온다.

프레젠트되는 뷰 컨트롤러가 프레젠트하는 뷰 컨트롤러에 반드시 데이터를 반환해야 한다면, 전달을 촉진시키기 위해 델리게이션 디자인 패턴을 사용하라. 델리게이션은 앱의 다른 부분에서 뷰 컨트롤러를 재사용하기 쉽게 해준다. 델리게이션을 사용하면 프레젠트되는 뷰 컨트롤러는 형식적인 프로토콜의 메소드를 구현하는 델리게이트 객체의 참조를 저장한다. 결과를 수집할 때, 프레젠트되는 뷰 컨트롤러는 델리게이트에서 있는 메소드들을 호출한다. 전형적인 구현에서, 프레젠트하는 뷰 컨트롤러는 그 자체를 프레젠트되는 뷰 컨트롤러의 델리게이트로 만든다.

Presenting a View Controller Defined in a Different Storyboard

같은 스토리보드에서 뷰 컨트롤러 간에 세그를 만들 수 있을지라도, 스토리보드 간에는 세그를 만들 수 없다. 다른 스토리보드에 있는 뷰 컨트롤러를 표시하고 싶다면, 반드시 프레젠트하기 전에 명시적으로 뷰 컨트롤러를 초기화해야 한다.

let sb = UIStoryboard(name: "SecodnStoryboard", bundle: nil)
let myVC = sb.instantiateViewController(withIdentifier: "MyViewController")!
self.present(myVC, animated: true, completion: nil)

앱에 여러 개의 스토리보드를 만드는 것에 대한 필요 조건은 없다. 하지만 여러 개의 스토리보드를 만드는 것이 유용할 수 있는 경우들이 있다.

  • 큰 프로그래밍 팀에 있고, 다른 부분의 유저 인터페이스가 팀의 다른 부분에 할당되었다. 각 팀은 논쟁을 최소화하기 위해 다른 스토리보드 파일에 유저 인터페이스의 일부분을 소유한다.
  • 뷰 컨트롤러 타입의 컬렉션을 미리 정의하는 라이브러리를 구입했거나 만들었다. 뷰 컨트롤러들의 컨텐츠는 라이브러리가 제공하는 스토리보드가 정의한다.
  • 외부 화면에 표시될 필요가 있는 컨텐츠를 가지고 있다. 이 경우 개별 스토리보드에 이차적인 화면과 연관된 모든 뷰 컨트롤러를 유지하고 있을 것이다. 같은 시나리오에 대한 대안 패턴은 커스텀 세그를 작성하는 것이다.