[UIKit-02] Login View(Textfield) 구성하기
Storyboard를 사용하지 않고, 코드로만 로그인을 위한 Textfield를 구성해보겠다.
우선 Login이라는 폴더를 생성하고, LoginViewController와 LoginView라는 파일을 생성 해주었다. 그리고 AppDelegate에서 rootViewController를 LoginViewController로 변경하고 backgroundColor는 원래대로 돌려 두겠다.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.backgroundColor = .systemBackground
window?.rootViewController = LoginViewController()
return true
}
}
이제 준비과정은 어느정도 끝났으니, 본격적으로 코드를 작성하면서 개념들을 정리하겠다.
1. LoginViewController.swift
style과 layout을 함수로 만들어서 이용을 하고자 한다.
import UIKit
class LoginViewController: UIViewController {
let loginView = LoginView()
override func viewDidLoad() {
super.viewDidLoad()
style()
layout()
}
}
extension LoginViewController {
private func style() {
loginView.translatesAutoresizingMaskIntoConstraints = false
}
private func layout() {
view.addSubview(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)
])
}
}
style부터 보자면, translatesAutoresizingMaskIntoConstraints을 false로 변경하였다.
굉장히 많이 나올텐데, 간단하게 말하자면 Storyboard가 아닌 코드로 Constraint를 조정할 때 사용한다.
딥하게 들어가면, translatesAutoresizingMaskIntoConstraints는 UIView의 프로퍼티로 true와 false를 통해 설정할 수 있다. 이들의 차이점을 이해하려면, AutoresizingMask에 대해서 알아야 한다. Superview가 커지거나 줄어듦에 따라 Subview의 크기나 위치를 조정하는 것이다. 이 또한 UIView의 인스턴트 프로퍼티이다.
다시 translatesAutoresizingMaskIntoConstraints로 돌아가보면, AutoresizingMask와 동일한 기능을 하는 autolayout이 함께 사용된다면 충돌이 일어날 수 있기에 Autoresizing을 사용하지 않겠다고 선언을 하는 것이 translatesAutoresizingMaskIntoConstraints = false 이다.
Storyboard를 통해 개발을 할 때, layout을 전혀 잡지 않으면 자기 멋대로 layout이 잡히는 경우를 많이 봤을 것이다.
그것이 true인 경우이고, Storyboard에서 layout을 잡으면 자동으로 이 값이 false로 지정이 되었었다.
그러나 이제 코드를 통해 View를 구성해야하니, translatesAutoresizingMaskIntoConstraints = false를 반드시 명시해줘야 우리가 원하는 대로 layout을 구성할 수 있다!
이제 layout으로 가보자. 우선 view.addSubview(loginView)를 통해 자식 View를 추가해준다. 그런 다음 NSLayout.Constraint.activate를 통해 그곳에서 코드를 작성하게 되는데, NSLayout.Constraint.activate는 무슨 의미일까? 이것도 굉장히 많이 사용되니 꼭 집고 넘어가도록 하자.
원래는 constraints를 추가하기 위해서 아래와 같은 방식으로 추가해줘야한다.
loginView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
loginView.leadingAnchor.constraint(equalToSystemSpacingAfter: view.leadingAnchor, multiplier: 1).isActive = true
view.trailingAnchor.constraint(equalToSystemSpacingAfter: loginView.trailingAnchor, multiplier: 1).isActive = true
그러나 activate Method를 이용하면 배열에 넣어 한번에 처리가 가능하다. 즉, 코드의 가독성이 올라가고 간편하여서 이렇게 사용하는 것이다. activate란 공식문서에 따르면 지정된 배열의 각 constraint을 활성화 한다는 뜻이다.
이제 세부적으로 코드에 대한 해석을 해보겠다.
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)
])
- loginView.centerYAnchor.constraint(equalTo: view.centerYAnchor)는 loginView를 superview인 view의 수직과 center로 동일하게 맞춘다는 뜻이다.
- loginView.leadingAnchor.constraint(equalToSystemSpacingAfter: view.leadingAnchor, multiplier: 1)는 leading을 설정하는데, 상위 view에 맞추되, multiplier: 1을 지정하여 8pts 여백을 준다는 뜻이다. 2는 16pts이다.
- view.trailingAnchor.constraint(equalToSystemSpacingAfter: loginView.trailingAnchor, multiplier: 1)는 trailing을 위와 같이 잡는다는 뜻이다.
그런데, 조금 특이한 점이 있다. center와 leading은 view에 맞췄는데, trailing은 반대로 view가 loginView를 기준으로 맞추고 있다. 이렇게 하는 이유는 view의 trailingAnchor가 loginView trailingAnchor 뒤에 오기 때문이다. 그래서 loginView.trailinigAnchor…로 작성을 하였을 때에는 원하는대로 레이아웃이 잡히지 않는 것이 확인되었다.
LoginView
이제 LoginView 코드를 작성해보자.
import Foundation
import UIKit
class LoginView: UIView {
let usernameTextField = UITextField()
override init(frame: CGRect) {
super.init(frame: frame)
style()
layout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
return CGSize(width: 200, height: 200)
}
}
extension LoginView {
func style() {
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .orange
usernameTextField.translatesAutoresizingMaskIntoConstraints = false
usernameTextField.placeholder = "Username"
usernameTextField.delegate = self
}
func layout() {
addSubview(usernameTextField)
NSLayoutConstraint.activate([
usernameTextField.topAnchor.constraint(equalToSystemSpacingBelow: topAnchor, multiplier: 1),
usernameTextField.leadingAnchor.constraint(equalToSystemSpacingAfter: leadingAnchor, multiplier: 1),
trailingAnchor.constraint(equalToSystemSpacingAfter: usernameTextField.trailingAnchor, multiplier: 1)
])
}
}
extension LoginView: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
usernameTextField.endEditing(true)
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if textField.text != "" {
return true
} else {
return false
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
}
}
LoginViewController와 마찬가지로 style과 layout을 설정해준다. 그리고 IntrinsicContentSize를 설정해주는데, 이는 콘텐츠의 본질적인 크기를 의미한다.
style부터 다시 살펴보자면, 위와 같이 translatesAutoresizingMaskIntoConstraints = false로 설정해주고, 확인을 위해 배경색을 orange로 해주었다. 이제 TextField를 추가해줄건데, 이것도 translatesAutoresizingMaskIntoConstraints를 false로 주고 placeholder와 delegate를 설정해주었다.
layout은 subview인 usernameTextField를 추가해주고, NSLayoutConstraint.activate를 통해 TextField의 layout을 잡아주었다.
마지막으로 TextField에 대한 Delegate를 설정해주는데, 아래와 같이 기본적인 틀을 잡아주면 된다.
이상으로 TextField를 추가했는데, username에 대한 것을 추가하였으니 다음 포스팅에서는 StackView를 구성하고 password에 대한 TextField를 구성해보겠다.
틀린 내용이나 궁금하신 사항은 언제든 Comment 환영합니다!!
댓글남기기