이번 포스팅에서는 UITextField 안에 버튼을 넣어서 isSecureTextEntry를 토글할 수 있는 Text Field를 만들어보겠습니다.
처음에 딱 떠오르는 생각은 아래처럼 secureButton 객체와 실행하려는 동작은 rx로 구현하고 addSubView를 통해서 구현하는 것입니다.
private let secureButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(named: Constant.Image.Eye.closed), for: .normal)
button.setImage(UIImage(named: Constant.Image.Eye.open), for: .selected)
return button
}()
private func bind() {
secureButton.rx.tap
.asDriver()
.drive(onNext: { [weak self] in
self?.secureButton.isSelected.toggle()
self?.isSecureTextEntry.toggle()
})
.disposed(by: disposeBag)
}
addSubview(secureButton)
secureButton.snp.makeConstraints { make in
make.top.equalToSuperview().offset(15)
make.bottom.equalToSuperview().offset(-15)
make.right.equalToSuperview().offset(-15)
make.width.equalTo(secureButton.snp.height)
}
하지만 이 방법은 치명적인 단점이 있습니다. UITextField가 FirstResponder인 경우, 즉 TextField 안에 텍스트를 수정하고 있을 때는 UITextField는 자신 내부에서 발생하는 모든 이벤트의 Responder가 됩니다. 따라서 UIButton인 secureButton에는 tap 이벤트가 전달되지 않는 것이죠.
UITextField에는 rightView라는 속성이 있습니다. 이 부분은 말 그대로 UITextField의 오른쪽 부분에 보여지는 View라는 뜻인데요. (leftView도 있습니다.) 이 rightView에 버튼을 넣게 되면 해당 버튼은 UITextField가 FirstResponder가 되더라도 Event를 전달 받을 수 있습니다. 별개의 View가 아니라 UITextField의 일부가 되기 때문입니다.
또한 rightViewRect라는 메소드를 통해서 rightView의 위치와 크기를 정해 줄 수 있습니다.
rightViewMode = .always
rightView = secureButton
override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.width - 30, y: 15, width: bounds.height - 30, height: bounds.height - 30)
}
많은 도움이 되었습니다, 감사합니다.