SegmentedControlとContainer View Controllersによるタブ切り替え
概要
-
SegmentedControl
の切り替えで、複数の子ViewControllerを切り替える
完成イメージ
特徴
- 子ViewControllerは、親ViewControllerと同じサイズにフィットさせる
- 子ViewControllerは、最初に呼ばれるまでインスタンス化されない
- 一度インスタンス化されるとプロパティにセットされているため、再度切り替え時でもすぐに使える
- 親ViewControllerは、SegmentedControlによる切り替えだけを担当し、子ViewControllerとの責務の分離ができる
- UITabBarController と同じような機能を自作する感じで、異なる点はViewControllerを配列形式で保持しない点
手順
-
SegmentedControl
をタップすることで、Sample1ViewController
とSample2ViewController
を切り替える場合の例
ViewControllerファイルの準備
- 親ViewControllerと2つの子ViewControllerを用意
- 子ViewControllerは、
Sample1ViewController
とSample2ViewController
の名前で作成
- 子ViewControllerは、
Storyboard側の準備
- ViewControllerを3つ配置
- 1つを親ViewController用にする
- ViewController部分を選択し
Editor
>Embed In
>Navigation Controller
から、ナビゲーションコントローラーを追加 - ナビゲーションコントローラーに、
Utility
パネル下部のShow the Object Library
からSegmented Control
をドラッグ&ドロップで追加
- ViewController部分を選択し
- 2つを子ViewController用にする
- 1つを
Custom Class
をSample1ViewController
にし、Storyboard ID
もSample1ViewController
にする- 切り替えが分かりやすいように、Viewの背景色を緑色に指定
- もう1つを
Custom Class
をSample2ViewController
にし、Storyboard ID
もSample2ViewController
にする- 切り替えが分かりやすいように、Viewの背景色を黄色に指定
- 1つを
Storyboardの親ViewControllerに設置したSegmentedControlをIBOutletで紐づけ
@IBOutlet weak var segmentedControl: UISegmentedControl!
子ViewControllerの追加/削除メソッド
private func add(asChildViewController viewController: UIViewController) {
// 子ViewControllerを追加
addChildViewController(viewController)
// Subviewとして子ViewControllerのViewを追加
view.addSubview(viewController.view)
// 子Viewの設定
viewController.view.frame = view.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// 子View Controllerへの通知
viewController.didMove(toParentViewController: self)
}
private func remove(asChildViewController viewController: UIViewController) {
// 子View Controllerへの通知
viewController.willMove(toParentViewController: nil)
// 子ViewをSuperviewから削除
viewController.view.removeFromSuperview()
// 子View Controllerへの通知
viewController.removeFromParentViewController()
}
親ViewControllerで、子ViewControllerの指定
private lazy var sample1ViewController: Sample1ViewController = {
let storyborad = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyborad.instantiateViewController(withIdentifier: "Sample1ViewController") as! Sample1ViewController
add(asChildViewController: viewController)
return viewController
}()
private lazy var sample2ViewController: Sample2ViewController = {
let storyborad = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyborad.instantiateViewController(withIdentifier: "Sample2ViewController") as! Sample2ViewController
add(asChildViewController: viewController)
return viewController
}()
SegmentedControl切り替え時のView更新
- Storyboardの親ViewControllerに設置した
Segmented Control
からIBAction
で紐づけ-
Connection
をAction
にする - メソッド名を
tapSegmentedControl
にし、Type
をUISegmentedControl
にする -
Type
をUISegmentedControl
にする
-
private func updateView() {
if segmentedControl.selectedSegmentIndex == 0 {
remove(asChildViewController: sample2ViewController)
add(asChildViewController: sample1ViewController)
} else {
remove(asChildViewController: sample1ViewController)
add(asChildViewController: sample2ViewController)
}
}
@IBAction func tapSegmentedControl(_ sender: UISegmentedControl) {
updateView()
}
viewDidLoad時の指定
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
private func setupView() {
updateView()
}
子ViewControllerが呼ばれた際の確認
- Sample1ViewController.swift
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("Sample1ViewController Will Appear")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Sample1ViewController Will Disappear")
}
- Sample2ViewController.swift
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("Sample2ViewController Will Appear")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Sample2ViewController Will Disappear")
}
親ViewControllerの完成コード
import UIKit
class ViewController: UIViewController {
// MARK: - Property
@IBOutlet weak var segmentedControl: UISegmentedControl!
private lazy var sample1ViewController: Sample1ViewController = {
let storyborad = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyborad.instantiateViewController(withIdentifier: "Sample1ViewController") as! Sample1ViewController
add(asChildViewController: viewController)
return viewController
}()
private lazy var sample2ViewController: Sample2ViewController = {
let storyborad = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyborad.instantiateViewController(withIdentifier: "Sample2ViewController") as! Sample2ViewController
add(asChildViewController: viewController)
return viewController
}()
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
// MARK: - View Methods
private func setupView() {
updateView()
}
private func updateView() {
if segmentedControl.selectedSegmentIndex == 0 {
remove(asChildViewController: sample2ViewController)
add(asChildViewController: sample1ViewController)
} else {
remove(asChildViewController: sample1ViewController)
add(asChildViewController: sample2ViewController)
}
}
// MARK: - Action
@IBAction func tapSegmentedControl(_ sender: UISegmentedControl) {
updateView()
}
// MARK: - Child View Controller Operation Methods
private func add(asChildViewController viewController: UIViewController) {
// 子ViewControllerを追加
addChildViewController(viewController)
// Subviewとして子ViewControllerのViewを追加
view.addSubview(viewController.view)
// 子Viewの設定
viewController.view.frame = view.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// 子View Controllerへの通知
viewController.didMove(toParentViewController: self)
}
private func remove(asChildViewController viewController: UIViewController) {
// 子View Controllerへの通知
viewController.willMove(toParentViewController: nil)
// 子ViewをSuperviewから削除
viewController.view.removeFromSuperview()
// 子View Controllerへの通知
viewController.removeFromParentViewController()
}
}
環境
- Xcode 9.4.1