2021/02/26現在編集中
ログイン画面の作成
1つ前の記事でユーザ登録画面を作った要領でログイン画面も作っていきます.
下記のような流れになるように作っていきます.
今回はおおまかに3つ
💡テキストボックスとボタンで構成されるログイン画面を作る
💡ログイン画面から新規登録画面に遷移するボタンがある
💡ログインしたらやわらかさを記入する画面に遷移する
これらの動きを持つ画面を作ります!
💡テキストボックスとボタンで構成されるログイン画面を作る
まずはユーザ名・パスワードを打つためのテキストボックス2つとログインボタンを作ります.一つ前の記事の要領でとりあえずviewDidLoadにぶちこんでます🙇🏻♂️
またtextFieldShouldReturnを使用して,テキストボックスに文字を入力して改行を押したらキーボードが隠れるようにします.これをしないとユーザー名などを打ち込んでもキーボードがしまえずログインボタンが押せないハメになります.
override func viewDidLoad() {
super.viewDidLoad()
print("ログインビューコントローラー")
self.viewModel = LoginViewModel()
self.view.backgroundColor = .white
self.userName.backgroundColor = UIColor(named: "textbox")
self.password.backgroundColor = UIColor(named: "textbox")
self.loginButton.backgroundColor = .systemGray
self.loginButton.tintColor = .white
self.loginButton.layer.cornerRadius = 10
// textFiel の情報を受け取るための delegate を設定するとtextFieldShouldReturnとかが呼ばれる
self.userName.delegate = self
self.password.delegate = self
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// キーボードを閉じる
textField.resignFirstResponder()
return true
}
💡ログイン画面から新規登録画面に遷移する
ログインボタンの下にある『新規登録する』(registraionButton)を押すと新規登録画面に遷移するようにします.
流れとしては
- LoginViewController で registraionButton の input(onTapRegistraionButton) を作ってTap判定する
- LoginViewModel で input の registraionButton を showRegistraionView にいれる
- LoginViewModel の output に showRegistraionView をいれる
- LoginViewController の output.showRegistraionView で遷移先のVCをstartする
のようになります.
1. LoginViewController で registraionButton の input(onTapRegistraionButton) を作ってTap判定する
とりあえずLoginViewModelのファイルだけ生成します.ファイルの新規作成をして中身は下記のように用意しておきます.
import Foundation
import RxSwift
import RxCocoa
class LoginViewModel: ViewModelType {
private let bag = DisposeBag()
func transform(input: Input) -> Output {
}
struct Input {
let onTapRegistraionButton: Signal<Void> // onTapRegistraionButtonをTapしたかをいれる
}
struct Output {
let showRegistraionView: Driver<Void> // 新規登録画面に遷移するかどうかをいれる
}
}
次にLoginViewControllerでLoginViewModelを宣言し,viewDidLoadでLoginViewModelのtransform関数を呼ぶようにします.
private var viewModel: LoginViewModel!
override func viewDidLoad() {
super.viewDidLoad()
...略
let input = createInput()
let output = viewModel.transform(input: input)
setupOutput(output)
}
さて中身を書いていきます❣️
LoginViewControllerで『registraionButtonを押した!』という判定をします.ここではRxSwiftのrx.tap.asSignal()
を使用します.
private func createInput() -> LoginViewModel.Input {
return LoginViewModel.Input(
onTapRegistraionButton: self.registraionButton.rx.tap.asSignal()
)
}
2. LoginViewModel で input の registraionButton を showRegistraionView にいれる
1のLoginViewControllerでTapしたかどうかを.emit
で監視します👀
『押された!』ってなったらshowRegistraionViewをacceptします.
func transform(input: Input) -> Output {
let showRegistraionView = PublishRelay<Void>()
input.onTapRegistraionButton
.emit(onNext: {
showRegistraionView.accept(())
})
.disposed(by: self.bag)
return LoginViewModel.Output(
showRegistraionView: showRegistraionView.asDriverOnErrorJustComplete()
)
}
3. LoginViewModel の output に showRegistraionView をいれる
2でacceptされたらOutputにいれることで『新規登録画面に遷移していいよ!』ってことを知らせます.
2のコードの
return LoginViewModel.Output(
showRegistraionView: showRegistraionView.asDriverOnErrorJustComplete()
)
ここの部分です.
4. LoginViewController の output.showRegistraionView で遷移先のVCをstartする
3のOutputでLoginViewModelから『新規登録画面に遷移していいよ!』と送られてきたかどうかを.drive(onNext:
で監視します👀
送られてきたら前の記事の要領でRegistrationViewController.start(self)
で画面遷移します!
private func setupOutput(_ output: LoginViewModel.Output) {
output.showRegistraionView
.drive(onNext: { [unowned self] in
RegistrationViewController.start(self)
}).disposed(by: bag)
}
以上で新規登録画面に遷移ができます!
前の記事から新規登録画面の見た目をすこし変えてしまいましたが,動きはこんな感じになります.
💡ログインしたらやわらかさを記入する画面に遷移する
途中です🙇🏻♂️
詰まったところ
private let viewModel: LoginViewModel
init(viewModel: LoginViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
このように書くとstartのところの
let nextVC = LoginViewController(nibName: "LoginView", bundle: nil)
でType of expression is ambiguous without more context
というエラーになってしまう.
なので今回はinitを省略しvarなどの宣言には!
をつけています.(!
がないと'LoginViewController' has no initializersになる)