[Swift] Custom Modal View

Judy·2023년 3월 8일
1

iOS

목록 보기
23/28
post-thumbnail

화면을 반만 띄우거나 중간에서 작게 띄우고 싶으면 어떻게 해야할까? 🤔

특정 정보를 띄우거나 사용자 입력을 받기 위한 화면이 전체 화면을 덮지 않고 일부분만 보이는 경우를 상용 앱에서도 심심치 않게 볼 수 있다.

일반적인 모달로 화면이동을 하면 화면 대부분을 덮기 때문에 여러 화면이 필요하다면 잦은 화면 이동으로 사용자에게 피로감을 줄 수 있다.

결론부터 말하자면 특정 위치에 특정 크기에 모달 뷰를 띄울 수 있는 방법은 UIPresentationController를 이용해 커스텀 모달 뷰를 만들어 사용하는 것이다!

우선 공식문서의 내용을 정리하면 다음과 같다.

UIPresentationController

전환 애니메이션과 뷰컨트롤러의 표시를 관리하는 객체

UIKit은 PresentationController를 통해 뷰컨트롤러가 표시되는 시간부터 사라질 때까지 프레젠테이션 프로세스에 관한 다양한 측면을 관리합니다. PresentationController를 사용하면 자체 애니메이션을 추가할 수 있고, 크기 변경 및 화면 표시 관련 측면을 관리할 수 있습니다.

다른 방식으로 프레젠테이션 동작을 수정하려는 경우 사용자 지정 PresentationController를 제공할 수 있습니다.

뷰 컨트롤러의 transitioning delegate를 통해 커스텀 PresentationController를 사용할 수 있습니다. UIKit은 뷰컨트롤러가 화면에 표시되는 동안 PresentationController 객체에 참조를 유지합니다.
-> UIViewControllerTransitioning

프레젠테이션 프로세스

  • 전환 애니메이션을 통해 새 뷰컨트롤러로 이동하는 작업
  • 새 뷰컨트롤러가 표시되는 동안 환경 변경(ex. 기기 회전)에 대한 응답
  • 전환 애니메이션을 통해 새 뷰컨트롤러 화면 밖으로 이동하는 작업

Methods to override

Instance Method
presentationTransitionWillBegin()
: 커스텀 뷰를 뷰 계층에 추가하고 해당 뷰의 appearance에 관한 애니메이션 수행

dismissalTransitionWillBegin()
: 뷰컨트롤러의 해제와 관련된 애니메이션을 수행

viewWillTransition(to:with:)
: 커스텀 뷰의 크기 관련 변경을 수행

Instance Property
frameOfPresentedViewInContainerView
: 애니메이션이 끝날 때 표시되는 보기에 할당할 프레임


UIViewControllerTransitioningDelegate

뷰컨트롤러 간의 fixed-length 또는 interactive transition를 관리하는 메서드 집합

custom modal presentation을 사용해 뷰컨트롤러를 표시하려면 modalPresentationStylecustom으로 설정하고, 이 프로토콜을 준수하는 객체를 transitioningDelegate 프로퍼티에 할당합니다. 해당 뷰컨트롤러를 present하면 UIKit은 뷰컨트롤러를 애니메이팅할 때transitioningDelegate를 쿼리합니다.

Getting the custom presentation controller

presentationController(forPresented:presenting:source:)
: 뷰컨트롤러 표시 시 뷰 계층을 관리할 커스텀 PresentationController의 delegate에게 요청하는 메서드

 optional func presentationController(
    forPresented presented: UIViewController,
    presenting: UIViewController?,
    source: UIViewController
) -> UIPresentationController?

Custom Modal View 예시

그래서 어떻게 구현하느냐! 실제로 코드로 적용해보면 다음과 같습니다.

1. 모달을 관리할 컨트롤러 생성

// Modal을 띄울 컨트롤러
final class CustomPresentationController: UIPresentationController {
 	
}

우선 모달로 띄울 뷰컨트롤러를 관리할 UIPresentationController를 정의합니다.

1. 모달의 크기와 위치 설정

// CustomPresentationController.swift
override var frameOfPresentedViewInContainerView: CGRect {
    let screenBounds = UIScreen.main.bounds
    // ModalView의 크기
    let size = CGSize(width: screenBounds.width,
                      height: screenBounds.height * 0.25)
	// ModalView의 위치
    let origin = CGPoint(x: .zero, y: screenBounds.height * 0.75)
    
    return CGRect(origin: origin, size: size)
}

그리고 frameOfPresentedViewInContainerView를 override하여 모달 뷰를 띄우고 싶은 위치와 크기를 지정해줍니다. 위 코드는 모달 뷰가 아래에서 일부만 보이도록 설정한 예시입니다.

3. 모달의 시작과 끝 구현

// CustomPresentationController.swift
override func presentationTransitionWillBegin() {
	super.presentationTransitionWillBegin()
    // 화면 전환하며 뷰가 나타날 때 실행할 코드
}

override func dismissalTransitionWillBegin() {
	super.dismissalTransitionWillBegin()
    // 화면이 사라질 때 실행할 코드
}

또한 모달 화면이 나타나고 사라질 때 설정해줘야 할 코드를 역시 override 메서드를 통해 설정해줍니다. 일반적으로 화면이 나타나고 사라지는 애니메이션을 추가할 수 있습니다.

4. 모달 델리게이트 설정

final class CustomTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
    
    func presentationController(forPresented presented: UIViewController,
                                presenting: UIViewController?,
                                source: UIViewController) -> UIPresentationController? {
        return CustomPresentationController(
            presentedViewController: presented,
            presenting: presenting
        )
    }
}

이후 UIViewControllerTransitioningDelegate을 상속하는 커스텀 델리게이트를 생성하고 presentationController 메서드가 커스텀한 PresentationController를 반환하도록 구현합니다.

6. 모달뷰 생성 및 델리게이트 지정

final class CustomViewController: UIViewController {
	weak var delegate: CustomTransitioningDelegate?
    private var customTransitioningDelegate = CustomTransitioningDelegate()
	
    // 뷰 컨트롤러 정의
    
    private func setupModalStyle() {
		modalPresentationStyle = .custom
  		modalTransitionStyle = .crossDissolve
		transitioningDelegate = customTransitioningDelegate
	}
}

마지막으로 실제로 모달로 띄울 뷰컨트롤러를 정의하고 modalPresentationStylecutom으로 설정하고 transitioningDelegate를 커스텀한 델리게이트로 지정해주면 끝!


7. 모달 띄우기

private func modalButtonTapped() {
	let customViewController = CustomViewController()
	customViewController.delegate = self
        
	present(customViewController, animated: true)
}

이후 구현한 모달을 present 해주면 원하는 위치와 크기로 띄워지는걸 확인할 수 있다 👍

예시 화면



++ 실제 사용한 코드는 아래 깃헙에서 참고해주세요! 🙇🏻‍♀️
Judy-999/ios-BoxOffice

혹시 잘못된 설명이나 코드가 있다면 알려주시면 감사하겠습니다 😊



참고하면 좋은 자료
Custom View Controller Presentation Tips & Tricks

profile
iOS Developer

0개의 댓글