https://developer.apple.com/documentation/uikit/uipresentationcontroller
"An object that manages the transition animations and the presentation of view controllers onscreen."
전환 애니메이션 및 뷰 컨트롤러 스크린의 프리젠테이션을 관리하는 객체입니다.
@MainActor class UIPresentationController : NSObject
뷰 컨트롤러가 표시될 때부터 해제될 때까지 UIKit
은 해당 뷰 컨트롤러에 대한 프리젠테이션 프로세스의 여러 측면을 관리하기 위해 프리젠테이션 컨트롤러를 사용합니다. 프리젠테이션 컨트롤러는 애니메이션 객체로부터 제공되는 애니메이션의 상단에 자신의 애니메이션을 추가할 수 있고, 크기 변경에 응답할 수 있으며, 뷰 컨트롤러가 스크린에 어떻게 표시될지의 여러 측면을 관리할 수 있습니다.
present(_:animated:completion:)
메소드를 사용해서 뷰 컨트롤러를 제시할 때 UIKit
은 프리젠테이션 프로세스를 항상 관리합니다. 해당 프로세스의 부분은 주어진 프리젠테이션 스타일에 적합한 프리젠테이션 컨트롤러 생성에 관여합니다. 내장된 스타일(UIModalPresentationStyle.pageSheet
스타일과 같은)의 경우 UIKit
은 필요한 프리젠테이션 컨트롤러 객체를 정의하고 생성합니다. 앱이 커스텀 프리젠테이션 컨트롤러를 제공할 수 있는 순간은 뷰 컨트롤러의 modalPresentationStyle
속성을 UIModalPresentationStyle.custom
으로 설정할 때뿐입니다. 제시되는 뷰 컨트롤러 아래에 그림자 뷰 혹은 장식 뷰를 추가하길 원할 때 혹은 다른 방식으로 프리젠테이션 동작 수정을 원할 때 커스텀 프리젠테이션 컨트롤러를 제공할 수 있습니다.
뷰 컨트롤러의 전환 딜리게이트를 통해 커스텀 프리젠테이션 컨트롤러를 제공할 수 있습니다. UIKit
은 제시된 뷰 컨트롤러가 스크린에 있는 동안 프리젠테이션 컨트롤러 객체에 대한 참조를 유지합니다. 전환 딜리게이트 및 제공하는 객체에 대한 더 많은 정보는 UIViewControllerTransitioningDelegate
를 보시기 바랍니다.
UIViewControllerTransitioningDelegate
https://developer.apple.com/documentation/uikit/uiviewcontrollertransitioningdelegate
https://velog.io/@panther222128/UIViewControllerTransitioningDelegate
프리젠테이션 컨트롤러에 의해 관리되는 프리젠테이션 프로세스는 세 가지 페이즈로 나눠집니다.
모든 페이즈가 발생하는 동안 프리젠테이션 컨트롤러의 역할은 커스텀 뷰 및 상태 정보를 관리하는 것입니다. 프리젠테이션 및 해제 페이즈 동안 프리젠테이션 컨트롤러는 커스텀 뷰를 뷰 계층구조에 추가하고 해당 뷰에 대한 적합한 전환 애니메이션을 생성합니다. 스크린에 나타나는 뷰 컨트롤러 뷰의 애니메이션은 애니메이터 객체에 의해 관리됩니다(즉 UIViewControllerAnimatedTransitioning
프로토콜을 채택하는 객체). UIKit
은 프리젠테이션 컨트롤러가 필요한 정리를 수행할 수 있도록 프리젠테이션 및 해제 페이즈의 시작과 끝에서 각각의 프리젠테이션 컨트롤러 메소드를 호출합니다.
UIPresentationController
클래스는 뷰 컨트롤러를 제시할 떄 뷰 계층구조 조작을 위한 구체적인 진입 시점을 정의합니다. 뷰 컨트롤러가 제시될 준비가 될 때 UIKit
은 프리젠테이션 컨트롤러의 presentationTransitionWillBegin()
메소드를 호출합니다. 뷰 계층구조에 뷰를 추가하기 위해 이 메소드를 사용할 수 있으며, 해당 뷰에 관련이 있는 모든 애니메이션 설정을 위해서도 이 메소드를 사용할 수 있습니다. 프리젠테이션 페이즈의 끝에서 UIKit
은 전환이 완료되었다는 것을 알 수 있도록 해주기 위해 presentationTransitionDidEnd(_:)
메소드를 호출합니다.
Listing 1은 커스텀 프리젠테이션 컨트롤러에 대한 presentationTransitionWillBegin()
및 presentationTransitionDidEnd(_:)
메소드의 샘플 구현을 보여주고 있습니다. 이 예시에서 뷰 컨트롤러는 제시된 뷰 컨트롤러에 백드롭처럼 흐린 뷰를 추가하고 있습니다. (_dimmingView
변수는 제공하려는 커스텀 UIView
객체를 참조하고 있습니다.) 뷰 컨트롤러를 제시할 때 presentationTransitionWillBegin()
메소드는 우선 흐린 뷰를 추가하고 흐린 뷰에 뷰 컨트롤러 컨텐트를 끼워넣습니다. 이후 다른 전환 애니메이션과 함께 작동하기 위한 페이드 인 애니메이션을 설정하고 있습니다. 사용자가 프리젠테이션 프로세스를 중지하면(아마도 상호작용 제스쳘르 통해) presentationTransitionDidEnd(_:)
는 흐린 뷰를 제거할 것입니다. 프리젠테이션이 완료되면 흐린 뷰와 제시된 뷰 컨트롤러는 해제 전까지 스크린에 남습니다.
Listing 1 Adding a custom view during a presentation
- (void)presentationTransitionWillBegin {
// Add a custom dimming view behind the presented view controller's view
[[self containerView] addSubview:_dimmingView];
[_dimmingView addSubview:[[self presentedViewController] view]];
// Use the transition coordinator to set up the animations.
id <UIViewControllerTransitionCoordinator> transitionCoordinator =
[[self presentingViewController] transitionCoordinator];
// Fade in the dimming view during the transition.
[_dimmingView setAlpha:0.0];
[transitionCoordinator animateAlongsideTransition:
^(id<UIViewControllerTransitionCoordinatorContext> context) {
[_dimmingView setAlpha:1.0];
} completion:nil];
}
- (void)presentationTransitionDidEnd:(BOOL)completed {
// Remove the dimming view if the presentation was aborted.
if (!completed) {
[_dimmingView removeFromSuperview];
}
}
뷰 컨트롤러를 해제할 때 모든 애니메이션 설정과 관련해 dismissalTransitionWillBegin()
메소드를 사용해야 하며, 뷰 계층구조로부터 커스텀 뷰를 제거하려면 dismissalTransitionDidEnd(_:)
메소드를 사용해야 합니다.
크기 클래스 변경은 앱이 컨텐트를 표시해야 하는 방법에 대한 큰 규모의 변경을 나타냅니다. 프리젠테이션 컨트롤러는 제시된 뷰 컨트롤러에 대해 프리젠테이션 스타일(필요한 경우) 조정을 통해 크기 클래스 변경을 관리합니다. 현재 프리젠테이션 스타일이 새 환경에서 합리적이지 않을 때에만 조정이 이뤄집니다. 예를 들어 크기 클래스가 수평 regular에서 수평 compact로 변경될 때 팝오버는 전체 스크린 프리젠테이션이 됩니다. 전체스크린 프리젠테이션처럼 새 환경에서도 이미 합리적인 프리젠테이션 스타일의 경우 적응적인 변경은 없습니다.
제시된 뷰 컨트롤러의 크기 클래스가 수평 regular에서 수평 compact로 변경될 때 프리젠테이션 컨트롤러는 어떤 새로운 스타일이 적용되어야 하는지 결정하기 위해 adaptivePresentationStyle
메소드를 호출합니다. 새 스타일이 필요한 경우 프리젠테이션 컨트롤러는 새로운 스타일로 진행하는 전환을 시작하며, 이 전환은 현재 프리젠테이션 컨트롤러 객체를 새로운 객체로 교체하기도 하는 전환입니다. 프리젠테이션 컨트롤러 객체가 변하기 때문에 제시된 뷰 컨트롤러의 presentationController
속성으로부터 프리젠테이션 컨트롤러를 회수해야 합니다.
프리젠테이션 스타일이 변하면 프리젠테이션 컨트롤러는 새롭게 제시된 뷰 컨트롤러를 구체화하기 위한 기회를 마련해줍니다. 전환을 시작하기 전에 프리젠테이션 컨트롤러는 자신이 갖는 딜리게이트 객체의 presentationController(_:viewControllerForAdaptivePresentationStyle:)
메소드를 호출합니다. 이 메소드를 구현하는 경우 제시된 컨텐트에 대한 주요 혹은 부수적인 조정을 수행하기 위해 이 메소드를 사용할 수 있습니다. 주요 조정은 현재 뷰 컨트롤러를 주어진 크기 클래스에서 구체적으로 디자인되었던 새 뷰 컨트롤러로 교체하는 것이 대표적입니다. 부수적인 조정은 새로운 크기 클래스에서 네비게이션 기능을 위해 네비게이션 컨트롤러 내부로 현재 뷰 컨트롤러를 설치하는 것이 대표적입니다.
크기 변경은 뷰 컨트롤러의 뷰가 갖는 넓이 혹은 높이에 대한 작은 변경을 나타냅니다. 이와 같은 변화는 기기가 portrait 및 landscape orientation 사이에서 회전할 때 발생합니다. 크기 변경이 발생하면 UIKit
은 프리젠테이션 컨트롤러의 viewWillTransition(to:with:)
메소드를 호출합니다. 커스텀 프리젠테이션에서 프리젠테이션 컨트롤러의 커스텀 뷰를 수정하거나 뷰 계층구조에 대한 변경사항을 만들기 위해 이 메소드를 사용하시기 바랍니다. 예를 들어 커스텀 장식 뷰를 새 크기에 더 잘맞는 다른 것으로 바꿀 수 있습니다.
프리젠테이션 컨트롤러에 임박한 크기 변경을 알려준 후 UIKit
은 보통의 뷰 레이아웃 프로세스를 시작합니다. 오토 레이아웃을 사용하는 앱은 오토 레이아웃 메커니즘이 필요한 경우에 따라 뷰의 크기를 조정하기 때문에 별도로 필요한 것은 없습니다. 커스텀 프리젠테이션 컨트롤러가 레이아웃 변경을 필요로 하는 경우 containerViewWillLayoutSubviews()
, containerViewDidLayoutSubviews()
메소드에서 그렇게 할 수 있습니다. 이와 같은 메소드는 UIViewController
클래스의 viewWillLayoutSubviews()
, viewDidLayoutSubviews()
메소드와 동일하며, 같은 방법으로 사용됩니다. UIKit
은 뷰 계층구조에서 뷰의 layoutSubviews()
메소드 호출 전후로 위 메소드들을 호출합니다.
커스텀 프리젠테이션 스타일의 경우 UIPresentationController
를 서브클래스해야 하고 커스텀 프리젠테이션 동작 구현을 위하 이 객체의 적어도 몇 가지 메소드를 오버라이드해야 합니다. 프리젠테이션 프로세스를 커스터마이징하려면 커스텀 프리젠테이션 컨트롤러를 사용하시기 바랍니다.
커스텀 프리젠테이션 컨트롤러의 경우 초기화 동안 init(presentedViewController:presenting:)
메소드를 호출해야 합니다. 이 메소드는 클래스의 지정된 이니셜라이저입니다. UIKit
은 이를 모든 프리젠테이션 객체에 대해 요구되는 이초기화를 수행하기 위해 사용합니다.
UIPresentationController
서브클래스가 하나 혹은 하나 이상의 커스텀 뷰를 관리하는 경우 아래 메소드 오버라이드를 고려해야 합니다.
presentationTransitionWillBegin()
메소드를 사용하시기 바랍니다. 뷰가 제시될 수 없는 경우 필요에 따라 presentationTransitionDidEnd(_:)
메소드에서 해당하는 뷰를 제거할 수 있습니다.dismissalTransitionWillBegin()
메소드를 사용하시기 바랍니다. dismissalTransitionDidEnd(_:)
메소드가 호출되기까지 뷰 계층구조에서 커스텀 뷰를 제거하지 않아야 합니다.viewWillTransition(to:with:)
메소드를 사용하시기 바랍니다.서브클래스는 커스텀 동작 제공이 필요한 경우에 따라 이 클래스의 다른 메소드를 오버라이드할 수 있습니다. 예를 들어 shouldPresentInFullscreen
혹은 frameOfPresentedViewInContainerView
메소드를 오버라이드 할 수 있고, 기본값 구현에서 제공하는 값과 다른 값을 반환할 수 있습니다.