今回はインターンの復習も兼ねて、簡単なアプリを作成しました。
題して、Delegateを使ったStoryboard要らずの画面遷移。
仕組みはとてもシンプルでボタンが押されたとき画面遷移する。画面遷移したページにあるボタンを押すと元のページに戻るというものです。
インターンを初めて1、2ヶ月目の頃大苦戦した記憶があります。
とりあえず大まかなやったことを書きます。
Storyboardの消去
まずは当然Storyboardの消去から。
参考にしたのはこのページです。
https://qiita.com/rika-tawashi/items/d975c2d9f85e8bb4aef5
手順は以下の4つ。
- プロジェクト作成
- 「Main.storyboard」を削除
- 「Info.plist」の「Main storyboard file base name」を「Main」→なし
- 「AppDelegate.swift」にビューを定義する
AppDelegate.swiftで以下のコードを入力します。
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = FirstViewController()
window?.makeKeyAndVisible()
return true
これによりFirstViewControllerが呼ばれます。
AutoLayoutの設定
次にAutoLayoutです。
let nextButton = UIButton()
view.addSubview(nextButton)
nextButton.translatesAutoresizingMaskIntoConstraints = false
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
nextButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
nextButton.heightAnchor.constraint(equalToConstant: 150.0).isActive = true
nextButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
-
addSubviewとはビューを追加するというものと自分は考えています。
なのでview.addSubview(nextButton)となります。 -
AutoresizingMaskをAuto Layoutに変換しないよう、translatesAutoresizingMaskIntoConstraintsをfalseにします。
-
NSLayoutAnchorを使って制約をします。centerXAnchorは水平方向の制約、centerXAnchorは垂直方向の制約です。
##呼び出し
-
ボタンが押されたとき関数nextButtonTappedが呼ばれます。それによりプライベート関数のshowNextViewControllerが呼ばれます。
-
showNextViewControllerでNextViewControllerのdelegateを自分にセットします。
-
modalTransitionStyleはモーダルの画面の切り替わり方を設定するものです。
参考にしたのはこのページです。
https://qiita.com/osamu1203/items/6c203f3f048f9d7540f3
これより画面遷移されてNextViewControllerが呼ばれます。
@objc func nextButtonTapped(_ sender: UIButton) {
showNextViewController()
}
private func showNextViewController() {
let nextVC = NextViewController()
nextVC.delegate = self
nextVC.modalTransitionStyle = UIModalTransitionStyle.flipHorizontal
present(nextVC, animated: true, completion: nil)
}
プロトコルの定義
- NextViewControllerにdelegateのためのプロトコル定義します。
- FirstViewControllerDelegateでdelegateを定義します。
- backButtonが押されたとき呼ばれます。
protocol FirstViewControllerDelegate: class {
func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton)
}
extension
最後にextensionでクラスを拡張します。これによってNextViewControllerでbackButtonが押されたとき先ほどのdelegateが呼ばれて、画面遷移が起こり画面が戻ってきます。
extension FirstViewController: FirstViewControllerDelegate {
func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton) {
dismiss(animated: true, completion: nil)
}
}
最後に
今後もちょっとずつ成果物をQiita等に上げていきたいなと思います!
おかしなところ、無駄なところがあればご指摘お願いします!
以下完成したコードになります。
import UIKit
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
let nextButton = UIButton()
nextButton.setTitle("Tap!", for: .normal)
nextButton.backgroundColor = UIColor.orange
nextButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 30.0)
nextButton.setTitleColor(UIColor.white, for: UIControl.State.normal)
nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside)
view.backgroundColor = UIColor.white
view.addSubview(nextButton)
nextButton.translatesAutoresizingMaskIntoConstraints = false
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
nextButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
nextButton.heightAnchor.constraint(equalToConstant: 150.0).isActive = true
nextButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
}
@objc func nextButtonTapped(_ sender: UIButton) {
showNextViewController()
}
private func showNextViewController() {
let nextVC = NextViewController()
nextVC.delegate = self
nextVC.modalTransitionStyle = UIModalTransitionStyle.flipHorizontal
present(nextVC, animated: true, completion: nil)
}
}
extension FirstViewController: FirstViewControllerDelegate {
func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton) {
dismiss(animated: true, completion: nil)
}
}
import UIKit
protocol FirstViewControllerDelegate: class {
func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton)
}
class NextViewController: UIViewController {
weak var delegate: FirstViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.orange
let backButton = UIButton()
backButton.setTitle("BACK", for: .normal)
backButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 30.0)
backButton.setTitleColor(UIColor.orange, for: UIControl.State.normal)
backButton.backgroundColor = UIColor.white
backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
view.backgroundColor = UIColor.orange
view.addSubview(backButton)
backButton.translatesAutoresizingMaskIntoConstraints = false
backButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
backButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
backButton.heightAnchor.constraint(equalToConstant: 150.0).isActive = true
backButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
}
@objc func backButtonTapped(_ sender: UIButton) {
delegate?.nextViewController(self, backButton: sender)
}
}
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = FirstViewController()
window?.makeKeyAndVisible()
return true
}
}