LoginSignup
41
47

More than 5 years have passed since last update.

コンテナview controllerを利用して、viewの一部にページコントロールを埋め込む

Posted at

iOSアプリのviewの一部分に、ページコントロールで切り替えられるviewを埋め込む実装をしたので、メモ。

完成のイメージはこんな感じ。

page_control_container.gif

動作環境

  • Xcode 7.3
  • iOS 9.3

実装

親view

まず親viewから。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let label = UILabel()
        label.frame.size = CGSize(width: 200, height: 100)
        label.center = view.center
        label.text = "ベースのview"
        label.textAlignment = .Center
        view.addSubview(label)

        // コンテナに追加
        let pageVC = PageViewController(transitionStyle: .Scroll,
                                        navigationOrientation: .Horizontal,
                                        options: nil)
        let pageViewHeight: CGFloat = 100
        pageVC.view.frame = CGRect(x: 0, y: view.bounds.size.height - pageViewHeight, width: view.bounds.size.width, height: pageViewHeight)

        addChildViewController(pageVC)
        view.addSubview(pageVC.view)
        pageVC.didMoveToParentViewController(self)
    }

}

PageViewController(後述) のインスタンスを、子viewのview controllerとして利用。

  • addChildViewController(_:)で、子のview controllerとして上記のPageViewControllerを追加
  • 子のviewを自身のviewに追加
  • didMoveToParentViewController(_:)を明示的に呼び出してview controllerの追加を終了する

子view

親viewの中に埋め込むview controllerを作成。

複数のviewを含むページコントロールとして実装するので、UIPageViewControllerを継承させる。同時にUIPageViewControllerDataSource, UIPageViewControllerDelegateを適用。

PageViewController.swift
import UIKit

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var contentVCs = [UIViewController]()
    var currentIndex: Int = 0

    // MARK: - View lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.blackColor()
        dataSource = self
        delegate = self

        for i in 0..<3 {
            let contentVC = PageContentViewController()
            contentVC.contentNumber = i
            contentVCs.append(contentVC)
        }
        setViewControllers([contentVCs[0]], direction: .Forward, animated: true, completion: nil)
    }

    // MARK: - UIPageViewControllerDataSource

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        guard let index = contentVCs.indexOf(viewController) where index != NSNotFound else { return nil }
        if index < contentVCs.count - 1 {
            return contentVCs[index + 1]
        } else {
            return contentVCs.first
        }
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        guard let index = contentVCs.indexOf(viewController) where index != NSNotFound else { return nil }
        if index > 0 {
            return contentVCs[index - 1]
        } else {
            return contentVCs.last
        }
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
        return contentVCs.count
    }

    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
        return currentIndex
    }

    // MARK: - UIPageViewControllerDelegate

    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        guard finished else { return }
        guard let contentVC = pageViewController.viewControllers?.first else { return }
        guard let index = contentVCs.indexOf(contentVC) where index != NSNotFound else { return }

        currentIndex = index
    }

}
  • viewDidLoad()で、ページコントロールの中身となるview controllerを3つセット。
    • setViewControllers(_:direction:animated:completion:)を利用
  • pageViewController(_:viewControllerBeforeViewController:), pageViewController(_:viewControllerAfterViewController:)で、表示中の前後のview controllerを指定。
    • 今回は行き止まりを作らず、無限にスクロールさせるようになっている
  • presentationCountForPageViewController(_:)で、ページインジケータの数をセット
    • 3個
  • presentationIndexForPageViewController(_:)でページインジケータのインデックス(位置)をセット
    • ページインジケータの現在のインデックス (currentIndex) を返す
  • pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)で、ページのtransitionが終了した時の処理を記述
    • currentIndexを更新

ページコントロールのコンテンツ部分のview controllerは以下のように実装。

contentNumberという変数を生成時に受け取り、それをページ番号として表示している。

PageContentViewController.swift
class PageContentViewController: UIViewController {

    var contentNumber: Int?

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let contentNumber = contentNumber else { return }
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 100))
        label.text = "\(contentNumber + 1)枚目"
        label.textColor = UIColor.whiteColor()
        label.textAlignment = .Center
        view.addSubview(label)
    }
}

おわり

以上で実装完了。

もう少し複雑ですが、yentaというiOSアプリで、こんな感じの実装をしました。

参考

41
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
47