ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • iOS) Presentation 과 Transition 그리고 Animation... (2)
    iOS 2020. 8. 10. 10:10

    Custom Presentation

    UI를 구성하는 기능은 View Controller가 VC에 화면을 표시하는 기능은 presentation controller가 담당한다.

    기본 presentation(ex.full screen, sheet..)을 사용한다면 Presentation Controller가 자동으로 생성된다. presentation을 custom으로 만든다면, 직접 presentation controller를 설정해주어야 한다. 이 presentation controller는 transition animation을 실행한다.

    custom view를 관리하는 것도 presentation controller의 역할이다.

    UIPresentationController 통해 presentation을 실행

    Presentation의 모든 것은 UIPresentationController에 들어있따!!

     

    들어가기 전 용어 정리

    • presentingViewController - 원래의 VC
    • presentedViewcontroller - 새롭게 표시될 viewController
    • containerView - presentation은 containerView 안에서 일어난다. 즉 presentedVC나 presentingVC 모두 containerView Frame 안에서 동작하는 것. transition, presentation 이 일어나는 동안에 superView 역할을 한다.

     

    Presentation의 실행 단계

    • presentation
    1. View Controller에서 새로운 화면을 표시하면 Transitioning Delegate에게 custom presentation controller를 요청
    2. Delegate가 controller를 리턴하면 custom presentation이 실행됨
    3. presentation controller에서 presentationTansitionWillBegin() 메소드를 실행 -> Transition에서 사용되는 CustomView를 추가하고 Animation에 필요한 속성을 설정한다.
    4. Transition이 실행되면서 화면이 실제로 전환됨. Transition(Animation)이 실행되는 동안 Presentation Controller에서 containerViewWillLayoutSubviews(), containerViewDidLayourSubviews() 메소드를 호출. 이 두개의 메소드를 통해서 커스텀 뷰의 배치를 구현한다.
    5. Transition이 완료되면 Presentation Controller에서 presentationTransitionDidEnd() 메소드가 실행되며, 여기까지 실행하면 preseneted VC가 화면에 표시되며 Management 단계로 넘어간다.
    • Management 
    1. 화면 회전 등 처리
    2. viewWillTransition(to:with:)메소드 호출
    3. AutoLayout을 사용한다면 따로 해줄 일은 없다.
    • Dismissal
    1. Presented View Controller를 닫으면dismissalTransitionWillBegin()메소드 호출과 함께 Dismissal 단계 시작
    2. Transition animation이 실행되는 동안 containerViewWillLayoutSubviews()와 containerViewDidLayoutSubviews()` 메소드 실행
    3. Transition이 완료되면 Presentation Controller에서dismissalTransitionDidEnd()메소드를 마지막으로 Presentation 마무리

     

    UIPresentationController를 이용하여 Custom Presentation을 만들어 보자

    들어가기 전에...

     

    • init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?)

    Initializes and returns a presentation controller for transitioning between the specified view controllers
    지정 생성자를 overriding 하고 presentation 대상 controller를 파라미터로 받는다.

     

    • presentedViewcontroller presentingViewcontroller

    각각 현재 present 되고 있는 VC와 이전의 VC의 속성이다.

     

    • overrid var frameOfPresentedViewInContainerView: CGRect { get}

    presentation은 containerView에서 실행된다. presented VC는 containerView 전체를 채우지만 해당 속성을 overriding 해서 Customize 할 수 있다.

    • var transitionCoordinator: UIViewControllerTransitionCoordinator? { get }

    해당 coordinator를 통해 presentation transition을 수행한다. 이 속성의 애니메이션이 presentation의 애니메이션이다.

     

    custom presentation을 presenting viewController에 fade away와 blur 효과를 주고 새로운 presented viewController는 화면의 반만 채우도록 만들어 보자.

    먼저 UIPresentationController를 생성한다.

    • init(presentedViewController: UIViewController, presenting: UIViewController?) 메소드를 통해 controller를 초기화 해준다.

    presentedViewcontroller에 사용할 닫기 버튼과 visualEffectView를 생성하고 init메소드를 통해 presentedViewcontroller에 쓰일 view들을 초기화 하자.

     

    • frameOfPresentedViewInContainerView: CGRect

    해당 속성을 통해 presentedViewController의 containerView의 frame을 지정 해준다. 또한 transition 과정에서 반복적으로 리턴 되기 때문에 되도록 이면 빨리 리턴 시켜놓는 것이 좋다.

    containerView의 크기가 곧 presentedViewcontroller의 크기이다.

    override var frameOfPresentedViewInContainerView: CGRect {
        guard var frame = containerView?.frame else {
            return .zero
        }
        frame.origin.y = frame.size.height / 2
        frame.size.height = frame.size.height / 2
            
        return frame
    }

     

    • presentationTransitionWillBegin()

    애니메이션에서 필요한 속성을 설정하고 실제 애니메이션을 구현하는 단계이다. presentationController에서 가장 중요한 포인트라고 할 수 있다.

    override func presentationTransitionWillBegin() { 
    	super.presentationTransitionWillBegin()
            
    	guard let containerView = containerView else { fatalError() } // 커스텀 뷰는 반드시 컨테이너 속성이 리턴하는 뷰에 추가해야 한다.
            
        dimmingView.alpha = 0.0
        dimmingView.frame = containerView.bounds
    	containerView.insertSubview(dimmingView, at: 0)
            
    	containerView.addSubview(closeButton)
    	closeButton.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
    	closeButtonTopConstraint = closeButton.topAnchor.constraint(equalTo: containerView.topAnchor, constant: -80)
    	closeButtonTopConstraint?.isActive = true
            
    	containerView.layoutIfNeeded()
            
    	closeButtonTopConstraint?.constant = 60
            
    	guard let coordinator = presentedViewController.transitionCoordinator else {
    	dimmingView.alpha = 1.0
    	presentingViewController.view.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
    	containerView.layoutIfNeeded()
    	return
    	}
            
    	coordinator.animate(alongsideTransition: { (context) in
    	self.dimmingView.alpha = 1.0
    	self.presentingViewController.view.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
    	containerView.layoutIfNeeded()
    	}, completion: nil)
    }

     

    • dismissalTransitionWillBegin()

    closeButton을 통해 presentedViewController를 dismiss 할 때 발생하는 animiation을 처리한다.

    override func dismissalTransitionWillBegin() {
    	print(String(describing: type(of: self)), #function)
    	closeButtonTopConstraint?.constant = -80
    	guard let coordinator = presentedViewController.transitionCoordinator else {
    		dimmingView.alpha = 0.0
    		presentingViewController.view.transform = CGAffineTransform.identity
    		containerView?.layoutIfNeeded()
    		return
    	}
    	coordinator.animate(alongsideTransition: { (context) in
    		self.dimmingView.alpha = 0.0
    		self.presentingViewController.view.transform = CGAffineTransform.identity
    		self.containerView?.layoutIfNeeded()
    	}, completion: nil)
    }

     

    • ViewController에서 TransitioningDelegate 채택
    class FadeAwayPresentationViewController: UIViewController {
    	override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            segue.destination.modalPresentationStyle = .custom
            segue.destination.transitioningDelegate = self
        }
    }
    extension FadeAwayPresentationViewController: UIViewControllerTransitioningDelegate {
        func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
            return FadeAwayPresentation(presentedViewController: presented, presenting: presenting )
        }
    }

     

    presentedViewcontroller의 modalPresentationStyle을 custom으로 바꾼 뒤 custom presentation controller를 요청할 수 있도록 transitioningDelegate를 채택한다.

    UIPresentationController를 이용한 custom presentation

     

    전체 소스 코드: https://github.com/uiyeonShin/Mastering_Animation/tree/master/Mastering_Animation/Fade%20Away%20Presentation

     

    iOS) Presentation 과 Transition 그리고 Animation... (3)

     

    iOS) Presentation 과 Transition 그리고 Animation... (3)

    Custom Transition transtion을 구성하는 6가지의 객체 - Animation Controller - Transtion Animation을 구현 UIViewControllerAnimatedTransitioning 프로토콜을 통해 구현 transition 시간과 animation을 구현..

    koggy.tistory.com

     

     

    댓글

Designed by Tistory.