내일 4시에 시험이라 공부해야하는데 갑자기 textfield에 꽂혀서 계속 이것만 만들었다...
우선 처음에 과제를 보자마자든 생각은 "그냥 만들면되겠네..."근데 학교에서 왔다갔다하는 지하철에서 드는생각이 아니이거 enum으로 타입을 나누고 타입별로 다르게 만들면 애초에 중복되는 코드들을 좀 없앨 수 있을까라는 생각이 문득 들었다.
그래도 월화 시험이 4개라서 셤끝나고 해야겠다 싶어서 참고있다가 이제 시험이 하나밖에 안남아서 그냥 좀 만들어봤다.
생각보다 이걸 만들면서 배웠던게 많다.
우선 저 텍스트필드 오른쪽에 들어가는 버튼을 custom하려면 rightview라는데다가 view를 넣어줘야하는데 하나를 넣는건 쉬운데 이게 두개를 어떻게 넣어야할지 먼저 고민을 해봤다. 그래서 그냥 view하나 만들어서 거기다가 버튼 두개 넣으면 되겠지?라는 생각을 했었는데
이게 문제가 두개를 오토레이아웃잡는게 쉽지가 않았다. 그래서 여기저기 찾아보니 frame으로 잡는거같았다. 그래서 프레임으로 잡았다. 그리고 안에들어갈 view들을 list로 묶으면 알아서 view의 크기와 내부 view의 크기를 적절히 잡을 수 있게 uiview에 익스텐션을 만들어서 사용했다
extension UIView {
func addButtonsInTextfield(views: [UIView]) -> UIView {
self.frame = .init(x: 0, y: 0, width: views.count * 20, height: 20)
views.enumerated().forEach { (index, view) in
view.frame = .init(x: 0 + (index * 20), y: 0, width: 20, height: 20)
self.addSubview(view)
}
return self
}
}
이걸만드는데 대체 이 리스트의 순서를 알게될까...고민을하다 enumerated쓰고 forEach돌리며되겠다 싶어서 그렇게 하니까 얼추 내가 원하는 모양으로 구현이가능해졌다
이제부턴 속전속결
enum TextFieldType {
case password
case email
}
타입지정하고 애초에 텍스트필드를 선언할때 타입을 init에서 받으면된다
var textfieldType: TextFieldType
init(textfieldType: TextFieldType) {
self.textfieldType = textfieldType
super.init(frame: .zero)
setup()
}
그리고 타입별로 선언할때는 이렇게
private func setup() {
self.backgroundColor = .white
switch textfieldType {
case .password:
isSecureTextEntry = true
rightView = buttonsView.addButtonsInTextfield(views: [clearButton, securityButton])
case .email:
isSecureTextEntry = false
rightView = buttonsView.addButtonsInTextfield(views: [clearButton])
}
rightViewMode = .never
self.layer.cornerRadius = 3
}
이렇게 하면 애초에 비밀번호텍스트필드면 clear버튼과 hide버튼이 함께 나오고 이메일텍스트필드면 clear버튼만 나온다.
사실 이정도만 하면 될 줄알았는데 이게 생각보다 까다로웠던게 추가로 구현했던기능이 텍스트필드를 누르면 focus되서 border line이 생기고 이런건데 이게 나는 추가로 정규식을 넣어서 string이 정규식이랑 다르면 error label이 뜨게 만들었는데 focus된 텍스트필드에서 다른 텍스트필드에 clear버튼을 누르면 당연히 string이 빈 문자열이 되어서 error label이 나와야되는데 이건 또 안나온다... 나와도 애니메이션 적용이 안되서 이거 해결할 방법을 생각하다가 결국 custom delegate로 해결했다
extension ViewController: ReloadErrorLabelDelegate {
func reloadLabelHeight(textField: UITextField) {
guard let textfield = textField as? CustomTextField, let passwordText = passwordTextfield.text else { return }
switch textfield.textfieldType {
case .email:
emailErrorHeight.isActive = false
case .password:
passwordErrorHeight.isActive = passwordText.checkPassword ? true : false
}
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
textField.becomeFirstResponder()
}
}
이렇게 하고 몇개의 오류를 해결하니 내가 원하는 방식으로 작동되고 애니메이션도 깔끔하게 동작하는 모습을 확인할 수 있었다.
아래는 최종 결과 영상이다
과제는 내일부터할거니까 우선 세부적인 UI는 생각안하고 기능만 구현해놨다