저번 포스팅에서 구현한 Stack View 내에 name과 password TextField를 나눠주는 divder를 추가하고, Sign-in button을 만들어 보자.

먼저 divider를 구현해보자.

divider

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 {
        if textField.text != "" {
            return true
        } else {
            return false
        }
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        
    }
}

우선 UIView를 가져와 dividerView를 선언한다.

그런 다음, style을 지정하는데 color 부분은 넘기고 layer.cornerRadius와 clipsToBounds를 주목해보자.

layer.cornerRadius는 StackView의 모서리를 둥글게 한다는 의미이다. Storyboard에서도 많이 사용하여서, 가볍게 넘기겠다.

clipsToBounds의 Default 값은 false인데, 이 값을 true로 설정하면 subview들이 receiver의 bounds에 clip 될 수 있다. 쉽게 말하자면, subview를 포함하는 view(receiver)가 잘릴 수 있다(clip)는 의미이다. true로 설정하면 subview가 view의 경계를 넘어가면 잘리게 되고, false면 경계를 넘어가도 잘리지 않게 된다는 의미이다.

여기서 왜 사용을 하였냐면, 위의 cornerRadius를 통해 StackView의 모서리를 둥글게 해주었는데 true로 설정을 하여 subview에 무언가가 채워질 때 StackView의 둥글게 된 틀에 따라 함께 잘리게 된다는 의미이다.

적절한 상위 view에 이 값을 설정해줘야 원하는 모양대로 나오게 된다.

layout()으로 넘어가보자. 여기서는 arangedSubviews 배열에 dividerView를 추가해주었다.

그런 다음, dividerView의 높이를 설정해 주었다. 속성이 하나 뿐이어서 NSLayoutConstraint가 아닌, 바로 설정을 해주었다.

Sign-in Button

이제 버튼을 만들어보자.

LoginViewController.swift

import UIKit

class LoginViewController: UIViewController {
    
    let loginView = LoginView()
    let signInButton = UIButton(type: .system)

    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)
    }
    
    private func layout() {
        view.addSubview(loginView)
        view.addSubview(signInButton)
        
        // 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)
        ])
        
    }
}

extension LoginViewController {
    @objc func signInTapped(sender: UIButton) {
        
    }
}

우선 UIButton인 signInButton을 선언해주자.

그런 다음, style()에서 signInButton의 속성들을 정해줄텐데, 우선 button에는 4가지 종류가 있다. Plain, Gray, Tinted, Filled로 되어있고, 나는 우선 filled로 구현을 하겠다.

그리고 imagePadding을 주었는데, 이는 indicator (button 클릭 시, 빙글빙글 도는 애니메이션 효과가 들어가기 위한 자리)를 위해 남겨두었다. 그런 다음, setTitle을 통해 안에 들어갈 text를 넣어준다. 여기서 for는 UIControl.State가 들어가는데, 이는 normal, highlighted, disabled, selected, focused, application, reserved의 상수를 받는다. 현재는 일반 버튼이기에, default인 normal로 남겨뒀다. addTarget을 통해 버튼을 클릭 이벤트로 어떠한 함수를 불러온다든지가 가능한데, 나중에 디테일하게 코드를 구현할 때 이부분에 대해서는 알아보도록 하겠다. (signInTapped을 그냥 넣어뒀지만 현재 아무런 기능은 하지 않는다.)

layout()으로 넘어가자! loginView와 마찬가지로 레이아웃을 잡아줄텐데, loginView를 기준으로 top은 16px만큼 띄워주고 leading과 trailing은 똑같이 맞추었다.

결과를 확인해보자!

태그:

카테고리:

업데이트:

댓글남기기