지난 포스팅까지는 Login 화면을 구축 하였었다. 이번 포스팅 부터 Onboarding 화면을 만들어 보겠다.

아래는 구현 할 화면이다. swaping을 통해 뷰가 전환 되는 형태이다.

Onboarding은 많은 어플리케이션에서 사용되고 있다. 주로 어플리케이션을 처음 설치한 유저들에게 어떠한 어플리케이션인지 간략하게 소개할 때 이용되는 것 같았다.

우선 전체 코드를 통해 차근차근 살펴보자.

Onboarding이라는 폴더를 하나 생성하였고, 하위에 OnboardingContainerViewController.swift 파일을 생성하였다.

그리고 시뮬레이터에서 확인을 위해 AppDelegate를 수정 해주겠다.

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.makeKeyAndVisible()
        window?.backgroundColor = .systemBackground
//        window?.rootViewController = LoginViewController()
        window?.rootViewController = OnboardingContainerViewController()

        return true
    }
}

다음은 OnboardingContainerViewController이다. 전체 코드를 보면서 중요한 부분은 체크하면서 넘어가자.

OnboardingContainerViewController.swift

import UIKit

class OnboardingContainerViewController: UIViewController {

    let pageViewController: UIPageViewController
    var pages = [UIViewController]()
    var currentVC: UIViewController {
        didSet {
        }
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)

        let page1 = ViewController1()
        let page2 = ViewController2()
        let page3 = ViewController3()

        pages.append(page1)
        pages.append(page2)
        pages.append(page3)

        currentVC = pages.first!

        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .systemPurple

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

        pageViewController.dataSource = self
        pageViewController.view.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            view.topAnchor.constraint(equalTo: pageViewController.view.topAnchor),
            view.leadingAnchor.constraint(equalTo: pageViewController.view.leadingAnchor),
            view.trailingAnchor.constraint(equalTo: pageViewController.view.trailingAnchor),
            view.bottomAnchor.constraint(equalTo: pageViewController.view.bottomAnchor),
        ])

        pageViewController.setViewControllers([pages.first!], direction: .forward, animated: false, completion: nil)
        currentVC = pages.first!
    }
}

// MARK: - UIPageViewControllerDataSource
extension OnboardingContainerViewController: UIPageViewControllerDataSource {

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        return getPreviousViewController(from: viewController)
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        return getNextViewController(from: viewController)
    }

    private func getPreviousViewController(from viewController: UIViewController) -> UIViewController? {
        guard let index = pages.firstIndex(of: viewController), index - 1 >= 0 else { return nil }
        currentVC = pages[index - 1]
        return pages[index - 1]
    }

    private func getNextViewController(from viewController: UIViewController) -> UIViewController? {
        guard let index = pages.firstIndex(of: viewController), index + 1 < pages.count else { return nil }
        currentVC = pages[index + 1]
        return pages[index + 1]
    }

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

    func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        return pages.firstIndex(of: self.currentVC) ?? 0
    }
}

// MARK: - ViewControllers
class ViewController1: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemRed
    }
}

class ViewController2: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemGreen
    }
}

class ViewController3: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBlue
    }
}

우선 UIPageViewController를 통해 pageViewController를 선언하였고, pages를 배열을 통해 가져온돠.

그리고 page들을 ViewController로써 추가를 해주고, currentVC를 pages배열의 가장 첫 index로 지정을 해준다.

주목할 부분이 있다.

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

3 Step에 의해서 child view controller가 추가된다.

  • 처음 addChild를 통해 child로 추가하고 싶은 ViewController를 파라미터로 넣게 된다.
  • child를 넣은 다음, addSubview를 통해 view에 추가하게 된다.
  • 마지막으로 didMove를 통하여 모든 UI ViewController 이벤트를 연결하게 된다. 이렇게 viewdidload, viewwillapper과 같은 일어나는 모든 life cycle를 포함하게 된다.

이 3가지 스텝은 Parent VC에 Child VC를 embed하고 싶을 때, 사용하게 되므로 꼭 기억하고 넘어가야겠다.

다음으로 pageViewController.dataSource = self 를 통해, 얼마나 많은 페이지가 있는지, 다음으로 보여져야할 페이지는 어떤 것인지 등을 넘겨주게 된다.

다른 것들은 기본적인 코드이므로, 읽어보면 바로 이해가 가능하여 설명은 생략하도록 하겠다.

태그:

카테고리:

업데이트:

댓글남기기