[UIKit-05] LoginView 마무리(Label, Handling)
이번 포스팅을 끝으로 Login화면을 완성시키자.
우선 ErrorMessage Label 부터 추가를 해보도록 하자.
LoginViewController.swfit
class LoginViewController: UIViewController {
let loginView = LoginView()
let signInButton = UIButton(type: .system)
let errorMessageLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
style()
layout()
}
}
extension LoginViewController {
private func style() {
loginView.translatesAutoresizingMaskIntoConstraints = false
signInButton.translatesAutoresizingMaskIntoConstraints = false
signInButton.configuration = .filled()
signInButton.configuration?.imagePadding = 8 // for indicator spacing
signInButton.setTitle("Sign In", for: [])
signInButton.addTarget(self, action: #selector(signInTapped), for: .primaryActionTriggered)
errorMessageLabel.translatesAutoresizingMaskIntoConstraints = false
errorMessageLabel.textAlignment = .center
errorMessageLabel.textColor = .systemRed
errorMessageLabel.numberOfLines = 0
errorMessageLabel.text = "Error failure"
errorMessageLabel.isHidden = false
}
.
.
.
// Error Label
NSLayoutConstraint.activate([
errorMessageLabel.topAnchor.constraint(equalToSystemSpacingBelow: signInButton.bottomAnchor, multiplier: 2),
errorMessageLabel.leadingAnchor.constraint(equalTo: signInButton.leadingAnchor),
errorMessageLabel.trailingAnchor.constraint(equalTo: signInButton.trailingAnchor)
])
.
.
전체 코드는 마지막에 공유하도록 하고, 새로 추가된 관련 부분만 체크하겠다. 우선 UILabel()인 errorMessageLabel을 선언하고, style()을 설정해준다. 특별한 것은 없지만, isHidden을 지정해줘서 앞으로 handling을 하고자 한다! false로 하면 label이 나타나고, true면 가려진다.
마지막으로 signInButton을 기준으로 layout을 잡아주었다.
이어서 이를 Handling 해보자.
LoginViewController.swfit
extension LoginViewController {
@objc func signInTapped(sender: UIButton) {
errorMessageLabel.isHidden = true
login()
}
private func login() {
guard let username = username, let password = password else {
assertionFailure("Username / password should never be nil")
return
}
if username.isEmpty || password.isEmpty {
configureView(withMessage: "Username / Password cannot be blank.")
return
}
if username == "Minjae" && password == "welcome" {
signInButton.configuration?.showsActivityIndicator = true
} else {
configureView(withMessage: "Incorrect Username / Password!")
}
}
private func configureView(withMessage message: String) {
errorMessageLabel.isHidden = false
errorMessageLabel.text = message
}
}
우선 signInTapped은 버튼을 눌렀을 때 불러오는 함수인데, isHidden을 true로 하여 가려주고, login 함수를 불러온다.
login 함수에서는 username과 password를 받는데, 이 값이 없다면 assertionFailure를 통해 메시지를 넣는데 이는 유저에게 보이는 것이 아니라 디버깅을 위한 것이다.
그 다음이 isEmpty를 통해 판별하여 유저에게 보여줄 메시지를 지정한다.
아직 database와 연동이 전혀 되지 않아 테스트를 위해 임의로 아이디와 비밀번호를 지정하여 성공, 실패를 판별하도록 하였다.
마지막 부분에 configureView라는 함수를 선언하였는데, message를 함께 받도록 하였다. 이러한 방식으로 함수를 사용하는 것은 매우 중요하고 편리함으로 더욱 친해지도록 하자.
아무튼 이 함수가 불러지는건 error가 있을 때이기에 isHidden을 끄고, text를 넣어 메시지를 띄워준다.
여기서 끝난 것이 아니다. LoginView.swift에서도 고쳐줄 것들이 남아 있다.
LoginView.swift
extension LoginView: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
usernameTextField.endEditing(true)
passwordTextField.endEditing(true)
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
}
}
특별한 것은 없지만, textFieldShouldEndEditing에서 if, else로 return을 바꿔주었는데 우선은 true로 해주겠다. 나중에 이 부분을 손볼 때, 자세히 알아보도록 하자.
마지막으로 Label을 띄워보자. TextField만 있으니 너무 허전하다.
LoginViewController
class LoginViewController: UIViewController {
let loginView = LoginView()
let signInButton = UIButton(type: .system)
let errorMessageLabel = UILabel()
let titleLabel = UILabel()
let subtitleLabel = UILabel()
.
.
.
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.textAlignment = .center
titleLabel.font = UIFont.preferredFont(forTextStyle: .largeTitle)
titleLabel.adjustsFontForContentSizeCategory = true
titleLabel.text = "Bankey"
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
subtitleLabel.textAlignment = .center
subtitleLabel.font = UIFont.preferredFont(forTextStyle: .title3)
subtitleLabel.adjustsFontForContentSizeCategory = true
subtitleLabel.numberOfLines = 0
subtitleLabel.text = "Your premium source for all things banking!"
.
.
.
// Title
NSLayoutConstraint.activate([
subtitleLabel.topAnchor.constraint(equalToSystemSpacingBelow: titleLabel.bottomAnchor, multiplier: 3),
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
// Subtitle
NSLayoutConstraint.activate([
loginView.topAnchor.constraint(equalToSystemSpacingBelow: subtitleLabel.bottomAnchor, multiplier: 3),
subtitleLabel.leadingAnchor.constraint(equalTo: loginView.leadingAnchor),
subtitleLabel.trailingAnchor.constraint(equalTo: loginView.trailingAnchor)
])
우선 UILabel로 title과 subtitle을 선언해주고, style()을 잡자. 그리고 layout()을 잡으면 된다. 특별히 까다로운 부분은 없어 설명은 생략하겠다.
전체 코드를 공유하며 마무리 하겠다.
LoginViewController.swift
import UIKit
class LoginViewController: UIViewController {
let loginView = LoginView()
let signInButton = UIButton(type: .system)
let errorMessageLabel = UILabel()
let titleLabel = UILabel()
let subtitleLabel = UILabel()
var username: String? {
return loginView.usernameTextField.text
}
var password: String? {
return loginView.passwordTextField.text
}
override func viewDidLoad() {
super.viewDidLoad()
style()
layout()
}
}
extension LoginViewController {
private func style() {
loginView.translatesAutoresizingMaskIntoConstraints = false
signInButton.translatesAutoresizingMaskIntoConstraints = false
signInButton.configuration = .filled()
signInButton.configuration?.imagePadding = 8 // for indicator spacing
signInButton.setTitle("Sign In", for: [])
signInButton.addTarget(self, action: #selector(signInTapped), for: .primaryActionTriggered)
errorMessageLabel.translatesAutoresizingMaskIntoConstraints = false
errorMessageLabel.textAlignment = .center
errorMessageLabel.textColor = .systemRed
errorMessageLabel.numberOfLines = 0
errorMessageLabel.isHidden = true
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.textAlignment = .center
titleLabel.font = UIFont.preferredFont(forTextStyle: .largeTitle)
titleLabel.adjustsFontForContentSizeCategory = true
titleLabel.text = "Bankey"
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
subtitleLabel.textAlignment = .center
subtitleLabel.font = UIFont.preferredFont(forTextStyle: .title3)
subtitleLabel.adjustsFontForContentSizeCategory = true
subtitleLabel.numberOfLines = 0
subtitleLabel.text = "Your premium source for all things banking!"
}
private func layout() {
view.addSubview(loginView)
view.addSubview(signInButton)
view.addSubview(errorMessageLabel)
view.addSubview(titleLabel)
view.addSubview(subtitleLabel)
// LoginView
NSLayoutConstraint.activate([
loginView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
// 1x = 8pts
loginView.leadingAnchor.constraint(equalToSystemSpacingAfter: view.leadingAnchor, multiplier: 1),
view.trailingAnchor.constraint(equalToSystemSpacingAfter: loginView.trailingAnchor, multiplier: 1)
])
// SignIn Button
NSLayoutConstraint.activate([
signInButton.topAnchor.constraint(equalToSystemSpacingBelow: loginView.bottomAnchor, multiplier: 2),
signInButton.leadingAnchor.constraint(equalTo: loginView.leadingAnchor),
signInButton.trailingAnchor.constraint(equalTo: loginView.trailingAnchor)
])
// Error Label
NSLayoutConstraint.activate([
errorMessageLabel.topAnchor.constraint(equalToSystemSpacingBelow: signInButton.bottomAnchor, multiplier: 2),
errorMessageLabel.leadingAnchor.constraint(equalTo: signInButton.leadingAnchor),
errorMessageLabel.trailingAnchor.constraint(equalTo: signInButton.trailingAnchor)
])
// Title
NSLayoutConstraint.activate([
subtitleLabel.topAnchor.constraint(equalToSystemSpacingBelow: titleLabel.bottomAnchor, multiplier: 3),
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
// Subtitle
NSLayoutConstraint.activate([
loginView.topAnchor.constraint(equalToSystemSpacingBelow: subtitleLabel.bottomAnchor, multiplier: 3),
subtitleLabel.leadingAnchor.constraint(equalTo: loginView.leadingAnchor),
subtitleLabel.trailingAnchor.constraint(equalTo: loginView.trailingAnchor)
])
}
}
extension LoginViewController {
@objc func signInTapped(sender: UIButton) {
errorMessageLabel.isHidden = true
login()
}
private func login() {
guard let username = username, let password = password else {
assertionFailure("Username / password should never be nil")
return
}
if username.isEmpty || password.isEmpty {
configureView(withMessage: "Username / Password cannot be blank.")
return
}
if username == "Minjae" && password == "welcome" {
signInButton.configuration?.showsActivityIndicator = true
} else {
configureView(withMessage: "Incorrect Username / Password!")
}
}
private func configureView(withMessage message: String) {
errorMessageLabel.isHidden = false
errorMessageLabel.text = message
}
}
LoginView.swift
import Foundation
import UIKit
class LoginView: UIView {
let stackView = UIStackView()
let usernameTextField = UITextField()
let passwordTextField = UITextField()
let dividerView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
style()
layout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension LoginView {
func style() {
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .secondarySystemBackground
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 8
usernameTextField.translatesAutoresizingMaskIntoConstraints = false
usernameTextField.placeholder = "Username"
usernameTextField.delegate = self
passwordTextField.translatesAutoresizingMaskIntoConstraints = false
passwordTextField.placeholder = "Password"
passwordTextField.isSecureTextEntry = true
passwordTextField.delegate = self
dividerView.translatesAutoresizingMaskIntoConstraints = false
dividerView.backgroundColor = .secondarySystemFill
layer.cornerRadius = 5
clipsToBounds = true
}
func layout() {
stackView.addArrangedSubview(usernameTextField)
stackView.addArrangedSubview(dividerView)
stackView.addArrangedSubview(passwordTextField)
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalToSystemSpacingBelow: topAnchor, multiplier: 1),
stackView.leadingAnchor.constraint(equalToSystemSpacingAfter: leadingAnchor, multiplier: 1),
trailingAnchor.constraint(equalToSystemSpacingAfter: stackView.trailingAnchor, multiplier: 1),
bottomAnchor.constraint(equalToSystemSpacingBelow: stackView.bottomAnchor, multiplier: 1)
])
dividerView.heightAnchor.constraint(equalToConstant: 1).isActive = true
}
}
extension LoginView: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
usernameTextField.endEditing(true)
passwordTextField.endEditing(true)
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
}
}
댓글남기기