import UIKit
// final > 클래스는 구조체 보다 느림 왜? 동적 디스패치 때문에, 테이블 디스패치가 일어나기 때문에
// final을 붙이면 더 이상 상속을 못하게 막으면서 메서드가 다이렉트 디스패치가 이루어 지도록 하는 것임
final class ViewController: UIViewController {
// MARK: - 이메일 입력하는 텍스트 뷰
// lazy 없이 그냥 선언하면 메모리에 동시에 올라가기 때문에
// addSubView하려면 메모리에 emailTextField,emailInfoLabel가 먼저 올라간 후에 return view에 올라가야함
private lazy var emailTextFieldView: UIView = {
let view = UIView()
view.backgroundColor = #colorLiteral(red: 0.3333333433, green: 0.3333333433, blue: 0.3333333433, alpha: 1)
view.layer.cornerRadius = 5
view.clipsToBounds = true
view.addSubview(emailTextField)
view.addSubview(emailInfoLabel) // 가장 위에 올라오는 것이 나중에 추가되야 함!
return view
}()
// "이메일 또는 전화번호" 안내문구
private let emailInfoLabel: UILabel = {
let label = UILabel()
label.text = "이메일주소 또는 전화번호"
label.font = UIFont.systemFont(ofSize: 18) // 글자 크기
label.textColor = #colorLiteral(red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 1)
return label
}()
// 로그인 - 이메일 입력 필드
private lazy var emailTextField: UITextField = {
var tf = UITextField()
tf.frame.size.height = 48
tf.backgroundColor = .clear
tf.textColor = .white
tf.tintColor = .white
tf.autocapitalizationType = .none // 자동으로 첫 글자 대문자
tf.autocorrectionType = .no // 자동으로 틀린글자 고쳐줌
tf.spellCheckingType = .no // 스펠링 체크
tf.keyboardType = .emailAddress
tf.addTarget(self, action: #selector(textFieldEditingChanged(_:)), for: .editingChanged)
return tf
}()
// MARK: - 비밀번호 입력하는 텍스트 뷰
private lazy var passwordTextFieldView: UIView = {
let view = UIView()
//view.frame.size.height = 48
view.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
view.layer.cornerRadius = 5
view.clipsToBounds = true
view.addSubview(passwordTextField)
view.addSubview(passwordInfoLabel)
view.addSubview(passwordSecureButton)
return view
}()
// 패스워드텍스트필드의 안내문구
private let passwordInfoLabel: UILabel = {
let label = UILabel()
label.text = "비밀번호"
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = #colorLiteral(red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 1)
return label
}()
// 로그인 - 비밀번호 입력 필드
private lazy var passwordTextField: UITextField = {
let tf = UITextField()
tf.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
tf.frame.size.height = 48
tf.backgroundColor = .clear
tf.textColor = .white
tf.tintColor = .white
tf.autocapitalizationType = .none
tf.autocorrectionType = .no
tf.spellCheckingType = .no
tf.isSecureTextEntry = true // 비밀번호 입력시 가리는 설정
tf.clearsOnBeginEditing = false
tf.addTarget(self, action: #selector(textFieldEditingChanged(_:)), for: .editingChanged)
return tf
}()
// 패스워드에 "표시"버튼 비밀번호 가리기 기능
private lazy var passwordSecureButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("표시", for: .normal)
button.setTitleColor(#colorLiteral(red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 1), for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .light)
button.addTarget(self, action: #selector(passwordSecureModeSetting), for: .touchUpInside)
return button
}()
// MARK: - 로그인버튼
private lazy var loginButton: UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = .clear
button.layer.cornerRadius = 5
button.clipsToBounds = true
button.layer.borderWidth = 1
button.layer.borderColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
button.setTitle("로그인", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.isEnabled = false // 초기엔 비활성화, 이메일 비밀번호 입력시 활성화 되도록 할 것임
button.addTarget(self, action: #selector(loginButtonTapped), for: .touchUpInside)
return button
}()
// 이메일텍스트필드, 패스워드, 로그인버튼 스택뷰에 배치
private lazy var stackView: UIStackView = {
let stview = UIStackView(arrangedSubviews: [emailTextFieldView, passwordTextFieldView, loginButton])
stview.spacing = 18
stview.axis = .vertical
stview.distribution = .fillEqually
stview.alignment = .fill
return stview
}()
// 비밀번호 재설정 버튼
private lazy var passwordResetButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.setTitle("비밀번호 재설정", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
button.addTarget(self, action: #selector(resetButtonTapped ), for: .touchUpInside)
return button
}()
// 3개의 각 텍스트필드 및 로그인 버튼의 높이 설정
private let textViewHeight: CGFloat = 48
// 오토레이아웃 향후 변경을 위한 변수(애니메이션)
lazy var emailInfoLabelCenterYConstraint = emailInfoLabel.centerYAnchor.constraint(equalTo: emailTextFieldView.centerYAnchor)
lazy var passwordInfoLabelCenterYConstraint = passwordInfoLabel.centerYAnchor.constraint(equalTo: passwordTextFieldView.centerYAnchor)
override func viewDidLoad() {
super.viewDidLoad()
print()
configure()
setupAutoLayout()
}
// 셋팅
private func configure() {
// view -> UIViewController에 이미 만들어져있는 기본 view 인스턴스
// addSubView -> 하위 뷰에 올려준다(?)는 의미
view.backgroundColor = #colorLiteral(red: 0.07450980392, green: 0.07450980392, blue: 0.07450980392, alpha: 1)
emailTextField.delegate = self
passwordTextField.delegate = self
[stackView, passwordResetButton].forEach { view.addSubview($0) }
}
// 오토레이아웃
private func setupAutoLayout() {
emailInfoLabel.translatesAutoresizingMaskIntoConstraints = false
emailInfoLabel.leadingAnchor.constraint(equalTo: emailTextFieldView.leadingAnchor, constant: 8).isActive = true
emailInfoLabel.trailingAnchor.constraint(equalTo: emailTextFieldView.trailingAnchor, constant: -8).isActive = true
// 고정된 코드
//emailInfoLabel.centerYAnchor.constraint(equalTo: emailTextFieldView.centerYAnchor).isActive = true
emailInfoLabelCenterYConstraint.isActive = true // 변수에 담은 애로 설정(애니메이션 때문에)
// Anchor 얼마 띄울건지. constraint 제약을 거는 것. equalTo 어디를 기준으로 맞출건지
// translatesAutoresizingMaskIntoConstraints -> 자동으로 autolayout 잡아주는 거 비활성화해두기, 우리가 수동으로 지정할 것이기 떄문!
emailTextField.translatesAutoresizingMaskIntoConstraints = false
emailTextField.topAnchor.constraint(equalTo: emailTextFieldView.topAnchor, constant: 15).isActive = true
emailTextField.bottomAnchor.constraint(equalTo: emailTextFieldView.bottomAnchor, constant: -2).isActive = true
emailTextField.leadingAnchor.constraint(equalTo: emailTextFieldView.leadingAnchor, constant: 8).isActive = true
emailTextField.trailingAnchor.constraint(equalTo: emailTextFieldView.trailingAnchor, constant: -8).isActive = true
passwordInfoLabel.translatesAutoresizingMaskIntoConstraints = false
passwordInfoLabel.leadingAnchor.constraint(equalTo: passwordTextFieldView.leadingAnchor, constant: 8).isActive = true
passwordInfoLabel.trailingAnchor.constraint(equalTo: passwordTextFieldView.trailingAnchor, constant: -8).isActive = true
//passwordInfoLabel.centerYAnchor.constraint(equalTo: passwordTextFieldView.centerYAnchor).isActive = true
passwordInfoLabelCenterYConstraint.isActive = true
passwordTextField.translatesAutoresizingMaskIntoConstraints = false
passwordTextField.topAnchor.constraint(equalTo: passwordTextFieldView.topAnchor, constant: 15).isActive = true
passwordTextField.bottomAnchor.constraint(equalTo: passwordTextFieldView.bottomAnchor, constant: -2).isActive = true
passwordTextField.leadingAnchor.constraint(equalTo: passwordTextFieldView.leadingAnchor, constant: 8).isActive = true
passwordTextField.trailingAnchor.constraint(equalTo: passwordTextFieldView.trailingAnchor, constant: -8).isActive = true
passwordSecureButton.translatesAutoresizingMaskIntoConstraints = false
passwordSecureButton.topAnchor.constraint(equalTo: passwordTextFieldView.topAnchor, constant: 15).isActive = true
passwordSecureButton.bottomAnchor.constraint(equalTo: passwordTextFieldView.bottomAnchor, constant: -15).isActive = true
passwordSecureButton.trailingAnchor.constraint(equalTo: passwordTextFieldView.trailingAnchor, constant: -8).isActive = true
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
stackView.heightAnchor.constraint(equalToConstant: textViewHeight*3 + 36).isActive = true
passwordResetButton.translatesAutoresizingMaskIntoConstraints = false
passwordResetButton.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 10).isActive = true
passwordResetButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
passwordResetButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
passwordResetButton.heightAnchor.constraint(equalToConstant: textViewHeight).isActive = true
}
// MARK: - 비밀번호 가리기 모드 켜고 끄기
@objc private func passwordSecureModeSetting() {
// 이미 텍스트필드에 내장되어 있는 기능
passwordTextField.isSecureTextEntry.toggle()
}
// 로그인 버튼 누르면 동작하는 함수
@objc func loginButtonTapped() {
// 서버랑 통신해서, 다음 화면으로 넘어가는 내용 구현
print("다음 화면으로 넘어가기")
}
// 리셋버튼이 눌리면 동작하는 함수
@objc func resetButtonTapped() {
//만들기
let alert = UIAlertController(title: "비밀번호 바꾸기", message: "비밀번호를 바꾸시겠습니까?", preferredStyle: .alert)
let success = UIAlertAction(title: "확인", style: .default) { action in
print("확인버튼이 눌렸습니다.")
}
let cancel = UIAlertAction(title: "취소", style: .cancel) { action in
print("취소버튼이 눌렸습니다.")
}
alert.addAction(success)
alert.addAction(cancel)
// 실제 띄우기
self.present(alert, animated: true, completion: nil)
}
// 앱의 화면을 터치하면 동작하는 함수
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
}
extension ViewController: UITextFieldDelegate {
// MARK: - 텍스트필드 편집 시작할때의 설정 - 문구가 위로올라가면서 크기 작아지고, 오토레이아웃 업데이트
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == emailTextField {
emailTextFieldView.backgroundColor = #colorLiteral(red: 0.2972877622, green: 0.2973434925, blue: 0.297280401, alpha: 1)
emailInfoLabel.font = UIFont.systemFont(ofSize: 11)
// 오토레이아웃 업데이트
emailInfoLabelCenterYConstraint.constant = -13
}
if textField == passwordTextField {
passwordTextFieldView.backgroundColor = #colorLiteral(red: 0.2972877622, green: 0.2973434925, blue: 0.297280401, alpha: 1)
passwordInfoLabel.font = UIFont.systemFont(ofSize: 11)
// 오토레이아웃 업데이트
passwordInfoLabelCenterYConstraint.constant = -13
}
// 실제 레이아웃 변경은 애니메이션으로 줄꺼야
UIView.animate(withDuration: 0.3) {
self.stackView.layoutIfNeeded()
}
}
// 텍스트필드 편집 종료되면 백그라운드 색 변경 (글자가 한개도 입력 안되었을때는 되돌리기)
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == emailTextField {
emailTextFieldView.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
// 빈칸이면 원래로 되돌리기
if emailTextField.text == "" {
emailInfoLabel.font = UIFont.systemFont(ofSize: 18)
emailInfoLabelCenterYConstraint.constant = 0
}
}
if textField == passwordTextField {
passwordTextFieldView.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
// 빈칸이면 원래로 되돌리기
if passwordTextField.text == "" {
passwordInfoLabel.font = UIFont.systemFont(ofSize: 18)
passwordInfoLabelCenterYConstraint.constant = 0
}
}
// 실제 레이아웃 변경은 애니메이션으로 줄꺼야
UIView.animate(withDuration: 0.3) {
self.stackView.layoutIfNeeded()
}
}
// MARK: - 이메일텍스트필드, 비밀번호 텍스트필드 두가지 다 채워져 있을때, 로그인 버튼 빨간색으로 변경
@objc private func textFieldEditingChanged(_ textField: UITextField) {
if textField.text?.count == 1 {
if textField.text?.first == " " {
textField.text = ""
return
}
}
guard
let email = emailTextField.text, !email.isEmpty,
let password = passwordTextField.text, !password.isEmpty
else {
loginButton.backgroundColor = .clear
loginButton.isEnabled = false
return
}
loginButton.backgroundColor = .red
loginButton.isEnabled = true
}
// 엔터 누르면 일단 키보드 내림
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
+ MVC 적용(Model이 따로 없어서 미구현)
Model - 비즈니스 로직(화면과 전혀 관련이 없는 로직과 데이터 관련)
View - UI관련. 즉, 사용자 화면 표시(뷰컨트롤러의 명령을 받아 화면 표시)
Controller - 뷰컨트롤러, 모델의 정보를 어떻게 뷰에 표시할지를 해석해서 전달(중재자)
View
import UIKit
class LoginView: UIView {
// MARK: - 이메일 입력하는 텍스트 뷰
private lazy var emailTextFieldView: UIView = {
let view = UIView()
view.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
view.layer.cornerRadius = 5
view.clipsToBounds = true
view.addSubview(emailTextField)
view.addSubview(emailInfoLabel)
return view
}()
// "이메일 또는 전화번호" 안내문구
private let emailInfoLabel: UILabel = {
let label = UILabel()
label.text = "이메일주소 또는 전화번호"
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = #colorLiteral(red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 1)
return label
}()
// 로그인 - 이메일 입력 필드
lazy var emailTextField: UITextField = {
var tf = UITextField()
tf.frame.size.height = 48
tf.backgroundColor = .clear
tf.textColor = .white
tf.tintColor = .white
tf.autocapitalizationType = .none
tf.autocorrectionType = .no
tf.spellCheckingType = .no
tf.keyboardType = .emailAddress
tf.addTarget(self, action: #selector(textFieldEditingChanged(_:)), for: .editingChanged)
return tf
}()
// MARK: - 비밀번호 입력하는 텍스트 뷰
private lazy var passwordTextFieldView: UIView = {
let view = UIView()
//view.frame.size.height = 48
view.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
view.layer.cornerRadius = 5
view.clipsToBounds = true
view.addSubview(passwordTextField)
view.addSubview(passwordInfoLabel)
view.addSubview(passwordSecureButton)
return view
}()
// 패스워드텍스트필드의 안내문구
private let passwordInfoLabel: UILabel = {
let label = UILabel()
label.text = "비밀번호"
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = #colorLiteral(red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 1)
return label
}()
// 로그인 - 비밀번호 입력 필드
lazy var passwordTextField: UITextField = {
let tf = UITextField()
tf.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
tf.frame.size.height = 48
tf.backgroundColor = .clear
tf.textColor = .white
tf.tintColor = .white
tf.autocapitalizationType = .none
tf.autocorrectionType = .no
tf.spellCheckingType = .no
tf.isSecureTextEntry = true
tf.clearsOnBeginEditing = false
tf.addTarget(self, action: #selector(textFieldEditingChanged(_:)), for: .editingChanged)
return tf
}()
// 패스워드에 "표시"버튼 비밀번호 가리기 기능
lazy var passwordSecureButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("표시", for: .normal)
button.setTitleColor(#colorLiteral(red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 1), for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .light)
button.addTarget(self, action: #selector(passwordSecureModeSetting), for: .touchUpInside)
return button
}()
// MARK: - 로그인버튼
lazy var loginButton: UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = .clear
button.layer.cornerRadius = 5
button.layer.borderWidth = 1
button.layer.borderColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
button.setTitle("로그인", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.isEnabled = false
//button.addTarget(self, action: #selector(loginButtonTapped), for: .touchUpInside)
return button
}()
// 이메일텍스트필드, 패스워드, 로그인버튼 스택뷰에 배치
private lazy var stackView: UIStackView = {
let stview = UIStackView(arrangedSubviews: [emailTextFieldView, passwordTextFieldView, loginButton])
stview.spacing = 18
stview.axis = .vertical
stview.distribution = .fillEqually
stview.alignment = .fill
return stview
}()
// 비밀번호 재설정 버튼
lazy var passwordResetButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.setTitle("비밀번호 재설정", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
//button.addTarget(self, action: #selector(resetButtonTapped), for: .touchUpInside)
return button
}()
// 3개의 각 텍스트필드 및 로그인 버튼의 높이 설정
private let textViewHeight: CGFloat = 48
// 오토레이아웃 향후 변경을 위한 변수(애니메이션)
lazy var emailInfoLabelCenterYConstraint = emailInfoLabel.centerYAnchor.constraint(equalTo: emailTextFieldView.centerYAnchor)
lazy var passwordInfoLabelCenterYConstraint = passwordInfoLabel.centerYAnchor.constraint(equalTo: passwordTextFieldView.centerYAnchor)
override init(frame: CGRect) {
super.init(frame: frame)
setup()
addViews()
setConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup() {
backgroundColor = #colorLiteral(red: 0.07450980392, green: 0.07450980392, blue: 0.07450980392, alpha: 1)
emailTextField.delegate = self
passwordTextField.delegate = self
}
func addViews() {
[stackView, passwordResetButton].forEach { addSubview($0) }
}
private func setConstraints() {
emailInfoLabelConstraints()
emailTextFieldConstraints()
passwordInfoLabelConstraints()
passwordTextFieldConstraints()
passwordSecureButtonConstraints()
stackViewConstraints()
passwordResetButtonConstraints()
}
private func emailInfoLabelConstraints() {
emailInfoLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
emailInfoLabel.leadingAnchor.constraint(equalTo: emailTextFieldView.leadingAnchor, constant: 8),
emailInfoLabel.trailingAnchor.constraint(equalTo: emailTextFieldView.trailingAnchor, constant: -8),
emailInfoLabelCenterYConstraint
])
}
private func emailTextFieldConstraints() {
emailTextField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
emailTextField.topAnchor.constraint(equalTo: emailTextFieldView.topAnchor, constant: 15),
emailTextField.bottomAnchor.constraint(equalTo: emailTextFieldView.bottomAnchor, constant: -2),
emailTextField.leadingAnchor.constraint(equalTo: emailTextFieldView.leadingAnchor, constant: 8),
emailTextField.trailingAnchor.constraint(equalTo: emailTextFieldView.trailingAnchor, constant: -8)
])
}
private func passwordInfoLabelConstraints() {
passwordInfoLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
passwordInfoLabel.leadingAnchor.constraint(equalTo: passwordTextFieldView.leadingAnchor, constant: 8),
passwordInfoLabel.trailingAnchor.constraint(equalTo: passwordTextFieldView.trailingAnchor, constant: -8),
passwordInfoLabelCenterYConstraint
])
}
private func passwordTextFieldConstraints() {
passwordTextField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
passwordTextField.topAnchor.constraint(equalTo: passwordTextFieldView.topAnchor, constant: 15),
passwordTextField.bottomAnchor.constraint(equalTo: passwordTextFieldView.bottomAnchor, constant: -2),
passwordTextField.leadingAnchor.constraint(equalTo: passwordTextFieldView.leadingAnchor, constant: 8),
passwordTextField.trailingAnchor.constraint(equalTo: passwordTextFieldView.trailingAnchor, constant: -8)
])
}
private func passwordSecureButtonConstraints() {
passwordSecureButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
passwordSecureButton.topAnchor.constraint(equalTo: passwordTextFieldView.topAnchor, constant: 15),
passwordSecureButton.bottomAnchor.constraint(equalTo: passwordTextFieldView.bottomAnchor, constant: -15),
passwordSecureButton.trailingAnchor.constraint(equalTo: passwordTextFieldView.trailingAnchor, constant: -8)
])
}
private func stackViewConstraints() {
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.centerXAnchor.constraint(equalTo: centerXAnchor),
stackView.centerYAnchor.constraint(equalTo: centerYAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 30),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -30),
stackView.heightAnchor.constraint(equalToConstant: textViewHeight*3 + 36)
])
}
private func passwordResetButtonConstraints() {
passwordResetButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
passwordResetButton.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 10),
passwordResetButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 30),
passwordResetButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -30),
passwordResetButton.heightAnchor.constraint(equalToConstant: textViewHeight)
])
}
// MARK: - 이메일텍스트필드, 비밀번호 텍스트필드 두가지 다 채워져 있을때, 로그인 버튼 빨간색으로 변경
@objc private func textFieldEditingChanged(_ textField: UITextField) {
if textField.text?.count == 1 {
if textField.text?.first == " " {
textField.text = ""
return
}
}
guard
let email = emailTextField.text, !email.isEmpty,
let password = passwordTextField.text, !password.isEmpty
else {
loginButton.backgroundColor = .clear
loginButton.isEnabled = false
return
}
loginButton.backgroundColor = .red
loginButton.isEnabled = true
}
// MARK: - 비밀번호 가리기 모드 켜고 끄기
@objc private func passwordSecureModeSetting() {
// 이미 텍스트필드에 내장되어 있는 기능
passwordTextField.isSecureTextEntry.toggle()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.endEditing(true)
}
}
extension LoginView: UITextFieldDelegate {
// MARK: - 텍스트필드 편집 시작할때의 설정 - 문구가 위로올라가면서 크기 작아지고, 오토레이아웃 업데이트
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == emailTextField {
emailTextFieldView.backgroundColor = #colorLiteral(red: 0.2972877622, green: 0.2973434925, blue: 0.297280401, alpha: 1)
emailInfoLabel.font = UIFont.systemFont(ofSize: 11)
// 오토레이아웃 업데이트
emailInfoLabelCenterYConstraint.constant = -13
}
if textField == passwordTextField {
passwordTextFieldView.backgroundColor = #colorLiteral(red: 0.2972877622, green: 0.2973434925, blue: 0.297280401, alpha: 1)
passwordInfoLabel.font = UIFont.systemFont(ofSize: 11)
// 오토레이아웃 업데이트
passwordInfoLabelCenterYConstraint.constant = -13
}
// 실제 레이아웃 변경은 애니메이션으로 줄꺼야
UIView.animate(withDuration: 0.3) {
self.stackView.layoutIfNeeded()
}
}
// 텍스트필드 편집 종료되면 백그라운드 색 변경 (글자가 한개도 입력 안되었을때는 되돌리기)
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == emailTextField {
emailTextFieldView.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
// 빈칸이면 원래로 되돌리기
if emailTextField.text == "" {
emailInfoLabel.font = UIFont.systemFont(ofSize: 18)
emailInfoLabelCenterYConstraint.constant = 0
}
}
if textField == passwordTextField {
passwordTextFieldView.backgroundColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
// 빈칸이면 원래로 되돌리기
if passwordTextField.text == "" {
passwordInfoLabel.font = UIFont.systemFont(ofSize: 18)
passwordInfoLabelCenterYConstraint.constant = 0
}
}
// 실제 레이아웃 변경은 애니메이션으로 줄꺼야
UIView.animate(withDuration: 0.3) {
self.stackView.layoutIfNeeded()
}
}
// 엔터 누르면 일단 키보드 내림
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Controller
import UIKit
final class ViewController: UIViewController {
private let loginView = LoginView()
override func loadView() {
// super.loadView() 필요없음
view = loginView
}
override func viewDidLoad() {
super.viewDidLoad()
print()
setupAddTarget()
}
func setupAddTarget() {
loginView.loginButton.addTarget(self, action: #selector(loginButtonTapped), for: .touchUpInside)
loginView.passwordResetButton.addTarget(self, action: #selector(resetButtonTapped), for: .touchUpInside)
}
// 로그인 버튼 누르면 동작하는 함수
@objc func loginButtonTapped() {
// 서버랑 통신해서, 다음 화면으로 넘어가는 내용 구현
print("다음 화면으로 넘어가기")
}
// 리셋버튼이 눌리면 동작하는 함수
@objc func resetButtonTapped() {
//만들기
let alert = UIAlertController(title: "비밀번호 바꾸기", message: "비밀번호를 바꾸시겠습니까?", preferredStyle: .alert)
let success = UIAlertAction(title: "확인", style: .default) { action in
print("확인버튼이 눌렸습니다.")
}
let cancel = UIAlertAction(title: "취소", style: .cancel) { action in
print("취소버튼이 눌렸습니다.")
}
alert.addAction(success)
alert.addAction(cancel)
// 실제 띄우기
self.present(alert, animated: true, completion: nil)
}
}
'iOS > UIKit' 카테고리의 다른 글
[UIKit] Alert (0) | 2023.11.12 |
---|---|
[UIKit] TextField Delegate (0) | 2023.11.12 |
[UIKit] autolayout, code base UI (0) | 2023.11.11 |