【swift】ちょい足しレシピ②!UIViewController達を制御するUIViewControllerさんを作ってみる+UINavigationControllerの様な遷移アニメーション付き
もくじ
毎度どうもこんにちは。iOSをメインに開発しているロッキーカナイです。
今回のちょい足しレシピは、複数のUIViewControllerを制御するUIViewControllerのお話です。
XCode9 / Swift4
実際にiOSの開発時に、
①アプリ画面の大部分で同じ様なナビゲーションバーを使用する
②各画面でナビゲーションバーのボタンの有無を変更する必要がある
③ナビゲーションバーのボタン制御を管理するクラスで統一したい
という点があり、題名にある通り、UIViewController達を制御するUIViewControllerを使用することで対応しました。
どういうものかと言うと、制御するUIViewController(次から親と言います)がNavigationBarを持っており、このNavigationBar上のボタンを選択すると親が現在表示しているUIViewController(次から子と言います)の状態を判断して切り替え等の動作を制御します。
よって、親が子を制御する構造になります。
このメリットとしては、
①ロジックは親のUIViewControllerが持つので管理し易く分かり易い
②子はUIViewControllerなのでstoryboardに追加できレイアウトが容易
が挙げられます。
親 ViewController
子 ViewControllerA / ViewControllerB
storyboardの記載は割愛します。
class ViewController: UIViewController {
enum CurrentPage {
case A
case B
}
// 制御するVC
let testA: TestViewControllerA = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "TestA") as! TestViewControllerA
let testB: TestViewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "TestB") as! TestViewControllerB
var currentPage: CurrentPage = .A
override func viewDidLoad() {
super.viewDidLoad()
// 初回表示のViewController
self.addChildViewController(testA)
self.view.addSubview(testA.view)
testA.didMove(toParentViewController: self)
self.title = testA.classTitle
// ナビゲーションボタン
let changeBtn: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(self.onSelectedChangeBtn(_:)))
self.navigationItem.setRightBarButtonItems([changeBtn], animated: true)
}
@objc func onSelectedChangeBtn(_ sender: Any) {
switch currentPage {
case .A:
moveViewControllerAnimation(fromVC: self.testA, toVC: self.testB, direction: .Push, completion: {isFinished in
self.title = self.testB.classTitle
})
case .B:
moveViewControllerAnimation(fromVC: self.testB, toVC: self.testA, direction: .Pop, completion: {isFinished in
self.title = self.testA.classTitle
})
}
currentPage = currentPage == .A ? .B : .A
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension ViewController {
enum TransitionDirection {
case Push
case Pop
}
// 遷移アニメーション
func moveViewControllerAnimation(fromVC: UIViewController, toVC: UIViewController, direction: TransitionDirection, completion: ((Bool) -> Void)? = nil){
switch direction {
case .Push:
var fromViewEndFrame = fromVC.view.frame
fromViewEndFrame.origin.x = -self.view.frame.size.width
toVC.view.frame = fromVC.view.frame
toVC.view.frame.origin.x = self.view.frame.size.width
UIView.animate(withDuration: 0.3, animations: {
fromVC.view.frame = fromViewEndFrame
toVC.view.frame.origin.x = 0
}, completion: { isFinished in
toVC.didMove(toParentViewController: self)
if let comp = completion {
comp(isFinished)
}
})
break
case .Pop:
var toViewStartFrame = toVC.view.frame
toViewStartFrame.origin.x = self.view.frame.size.width
toVC.view.frame.origin.x = -self.view.frame.size.width
fromVC.willMove(toParentViewController: nil)
UIView.animate(withDuration: 0.3, animations: {
toVC.view.frame.origin.x = 0
fromVC.view.frame = toViewStartFrame
}, completion: { isFinished in
fromVC.removeFromParentViewController()
if let completion = completion {
completion(isFinished)
}
})
break
}
}
}
class TestViewControllerA : UIViewController {
var classTitle: String = "TestA"
}
class TestViewControllerB : UIViewController {
var classTitle: String = "TestB"
}
UINavigationViewControllerの様にアニメーションも可能ですので、複数の画面を制御する様にしたい場合には使えるかと思います。
以上、「ちょい足しレシピシリーズ UIViewController達を制御するUIViewController」でした!