UIPageViewController 심화 활용: 고급 페이지 네비게이션

작성일 :

UIPageViewController 심화 활용: 고급 페이지 네비게이션

UIPageViewController는 iOS 앱에서 여러 페이지의 콘텐츠를 표시할 때 유용하게 사용할 수 있는 강력한 클래스입니다. 기본적인 사용법은 이미 많은 곳에서 다루어지고 있으나, 이번 글에서는 보다 고급스러운 기능을 활용하여 페이지 네비게이션을 심화 구현하는 방법에 대해 논의하고자 합니다.

기본 설정에서 고급 설정으로

기본적으로 UIPageViewController는 초기 세팅부터 시작합니다. 아래와 같이 기본 설정을 마친 후, 데이터 소스와 델리게이트를 설정할 수 있습니다.

swift
import UIKit

class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var pageViewController: UIPageViewController!
    var pageContent: [UIViewController] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        setupPageViewController()
    }

    private func setupPageViewController() {
        let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
        pageVC.dataSource = self
        pageVC.delegate = self

        if let firstVC = pageContent.first {
            pageVC.setViewControllers([firstVC], direction: .forward, animated: true, completion: nil)
        }

        self.addChild(pageVC)
        self.view.addSubview(pageVC.view)
        pageVC.didMove(toParent: self)

        self.pageViewController = pageVC
    }
}

위의 코드는 기본적인 UIPageViewController의 설정을 보여줍니다. 하지만 이를 심화 활용하기 위해서는 몇 가지 더 알아야 할 점이 있습니다.

페이지 전환 애니메이션의 커스터마이징

기존의 UIPageViewController는 몇 가지 기본 애니메이션 스타일을 제공합니다. 하지만 원하는 대로 애니메이션을 커스터마이즈하기 위해 몇 가지 트릭을 사용하는 것이 필요합니다.

사용자 정의 전환 애니메이터 구현

사용자 정의 애니메이터를 만들려면 UIViewControllerAnimatedTransitioning 프로토콜을 채택한 클래스를 구현해야 합니다.

swift
import UIKit

class CustomPageTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval = 0.5

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromVC = transitionContext.viewController(forKey: .from) else { return }
        guard let toVC = transitionContext.viewController(forKey: .to) else { return }

        let containerView = transitionContext.containerView
        containerView.addSubview(toVC.view)

        toVC.view.alpha = 0.0
        UIView.animate(withDuration: duration, animations: {
            toVC.view.alpha = 1.0
        }) { _ in
            fromVC.view.removeFromSuperview()
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

이제 위에서 만든 커스텀 애니메이터를 UIPageViewController에 적용하는 방법을 살펴보겠습니다. UIPageViewControllerDelegate 메서드를 통해 사용자 정의 전환 애니메이터를 반환합니다.

swift
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
    // Custom logic before transition
}

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    // Custom logic after transition
}
}

func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewController.SpineLocation {
    return .none
}

func presentationCount(for pageViewController: UIPageViewController) -> Int {
    return pageContent.count
}

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
    guard let currentVC = pageViewController.viewControllers?.first else { return 0 }
    return pageContent.firstIndex(of: currentVC) ?? 0
}

애니메이션 적용

이제 사용자 정의 애니메이션을 실제로 적용해 보겠습니다. UIPageViewControllerDelegateanimationControllerForPresentedController 메서드를 구현하여, 커스텀 애니메이터를 반환하도록 합시다.

swift
func pageViewController(_ pageViewController: UIPageViewController, animationControllerForPresentedController presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return CustomPageTransitionAnimator()
}

위의 방법을 통해, 페이지 전환 시 사용자 정의 애니메이션이 적용됩니다. 또한, UIViewControllerContextTransitioning을 활용하면 더욱 다양한 애니메이션을 구현할 수 있습니다.

데이터 소스 관리 고급 설정

데이터 소스 관리에서는 UIPageViewControllerDataSource 프로토콜을 통해 여러 페이지의 내용 관리가 가능합니다. 다음은 이전, 다음 컨트롤러를 관리하는 기본적인 방법입니다.

swift
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
    guard let index = pageContent.firstIndex(of: viewController), index > 0 else { return nil }
    return pageContent[index - 1]
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
    guard let index = pageContent.firstIndex(of: viewController), index < pageContent.count - 1 else { return nil }
    return pageContent[index + 1]
}

스냅샷을 통한 성능 최적화

고급 기능을 구현할 때 중요한 점은 성능 최적화입니다. 특히 페이지 전환 시 각각의 페이지에 대해 스냅샷을 만들어 두면 전환 성능이 대폭 향상됩니다.

스냅샷 저장 및 로드

각 페이지의 스냅샷을 저장하고, 페이지 전환 시 이를 로드하는 방법을 살펴봅시다.

swift
func saveSnapshots() {
    for (index, viewController) in pageContent.enumerated() {
        let view = viewController.view.snapshotView(afterScreenUpdates: true)
        pageSnapshots[index] = view
    }
}

func loadSnapshot(for index: Int) -> UIView? {
    return pageSnapshots[index]
}

스냅샷을 저장하고 로드하는 방법을 통해, 페이지 전환 시에 발생하는 비용을 줄일 수 있으며 따라서 성능을 최적화할 수 있습니다.

결론

UIPageViewController는 iOS 앱에서 페이지 기반 네비게이션을 구현하는 매우 유용한 도구입니다. 기본 설정을 넘어서 고급 기능을 활용하면 더욱 효과적이고 매력적인 사용자 경험을 제공할 수 있습니다. 페이지 전환 애니메이션 커스터마이즈, 데이터 소스 관리 고급 설정, 성능 최적화 등의 방법을 통해 UIPageViewController를 심화 활용하는 방법을 충분히 익히셨길 바랍니다.