시나리오 : SnapKit과 RxSwift를 사용하여 TextField 클릭 시 키보드 높이에 맞춰 하단 버튼의 위치를 변경해주고 싶음
AS-IS
기존에 구현했던 방법 -> 스토리보드에 화면 구성을 하고 키보드 높이에 따라 버튼의 위치를 변경해줬던 부분
class ViewController: UIViewController {
@IBOutlet weak var pinNumberTextfield: UITextField!
@IBOutlet weak var nextBtnBottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.navigationItem.title = "created by using storyboard"
}
@IBAction func nextBtnPressed(_ sender: UIButton) {
self.pinNumberTextfield.resignFirstResponder()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.regiterNotifications()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.unRegisterNotification()
}
}
extension ViewController {
func regiterNotifications(){
NotificationCenter.default.addObserver(self, selector: #selector(keyboardEvent), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardEvent), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func unRegisterNotification(){
NotificationCenter.default.removeObserver(self,name:UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self,name:UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardEvent(notiInfo: Notification){
guard let userInfo = notiInfo.userInfo else { return }
guard let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
if notiInfo.name == UIResponder.keyboardWillShowNotification {
//키보드 높이 + safeArea 하단 영역(X이후 버전대응을 위해서)
self.nextBtnBottomConstraint.constant = keyboardFrame.height - self.view.safeAreaInsets.bottom
}else{
self.nextBtnBottomConstraint.constant = 0
}
}
}
To-BE
SnapKit을 통해서 화면구성을 해주고 RxSwift를 이용하여 구현
func keyboardHeight() -> Observable<CGFloat> {
return Observable
.from([
NotificationCenter.default.rx.notification(UIResponder.keyboardWillShowNotification)
.map { notification -> CGFloat in
(notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height ?? 0
},
NotificationCenter.default.rx.notification(UIResponder.keyboardWillHideNotification)
.map { _ -> CGFloat in
0
}
])
.merge()
}
//How to use it
let disposeBag = DisposeBag()
func drawCustomUI(){
...
keyboardHeight()
.observe(on: MainScheduler.instance)
.subscribe(onNext: { keyboardHeight in
let safeAreaBottom = safeArea?.bottom ?? 0
let height = keyboardHeight > 0.0 ? (keyboardHeight - safeAreaBottom) : safeAreaBottom
self.updateNextBtnBottom(-height)
})
.disposed(by: disposeBag)
...
}
func updateNextBtnBottom(_ offset: CGFloat){
self.nextButton.snp.remakeConstraints {
//bottom offset 설정
$0.bottom.equalTo(safeAreaLayoutGuide.snp.bottom).offset(offset)
$0.left.equalTo(0)
$0.right.equalTo(0)
$0.height.equalTo(50)
}
}
각 각 코드 작성 후 실행 화면
마무리
SnapKit 으로 화면 구성하는 것은 적응하는데 금방 될 거 같음.
RxSwift는 공부를 좀 더 해야겠지만 확실히 코드량이나 가독성 부분에서 좋아 보임.
관련 자료
GitHub:
https://github.com/PotatoArtie/Potato-iOS/tree/master/Labs/KeyboardHeightPotato
댓글 영역