iOS 앱을 만들다 보면 가장 처음 접하게 되는 문제가 이 키보드 가림 문제이다.
보통 책이나 웹상에 떠도는 소스들을 보다보면 매우 간단하게 UITextFiled 하나만 배치하여 키보드가 나타나면 뷰를 올려주고 키보드가 내려가면 다시 뷰를 내려주는 단순한 상황만 언급할 뿐 실제 현업에서 발생 가능한 UITextField가 여러개일 때
즉 상단에 위치한 UITextField컨트롤은 키보드가 보여줘도 그대로 놔둬야 하고 하단에 위치한 UITextField 컨트롤은 키보드만큼 올려줘야 하는 상황에 대해 제대로 해결책을 제시하는 글은 찾기 힘들다.
오늘 소개할 이 방법 말고도 여러 방법들이 있겠지만 초보자도 쉽게 따라할 수 있는 방법을 택하여 소개하고자 한다.
대략 순서는 이러하다.
1. viewDidLoad에서 UITextField Delegate 연결
2. viewDidLoad에서 NotificationCenter를 이용하여 Observer 등록 : 키보드 Show, Hide 이벤트 확인
3. UITextField가 키보드에 가려졌는지 확인을 위한 해당 컨트롤의 위치좌표(Y) 확인
4. 가려졌다면 뷰 이동 O, 안가려졌다면 뷰 이동 X
5. 모든 작업 종료 후 viewWillDisappear에서 2번에서 등록했던 Observer 제거
1. TextField의 처리를 위해 UITextFieldDelegate 프로토콜 추가
(이후 TextField 컨트롤은 편의상 컨트롤이라 칭함)
class MyViewController: UIViewController, UITextFieldDelegate {
}
2. 컨트롤 변수와 컨트롤을 연결(너무 기초라 패스)
위에서부터 순서대로 txtTmp, txtId, txtPw
@IBOutlet weak var txtTmp: UITextField!
@IBOutlet weak var txtId: UITextField!
@IBOutlet weak var txtPw: UITextField!
3. viewDidLoad()에서 컨트롤 변수의 delegate 연결 및 키보드를 내리기 위해 완료 버튼(done)을 추가해준다.
txtTmp.delegate = self
txtId.delegate = self
txtPw.delegate = self
txtTmp.returnKeyType = .done
txtId.returnKeyType = .done
txtPw.returnKeyType = .done
4. 키보드가 올라왔나 내려갔나 확인을 위해 NotificationCenter로 Observer 등록 NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
이렇게 구현하면 keyboardWillShow, Hide가 없다고 에러가 뜰텐데 원칙상 선 구현 후 정의를 내려야 하지만 편의상 그냥 구현한다.
5. 키보드가 올라왔을 때 컨트롤이 키보드에 가려졌을 때 뷰를 그만큼 올려주는 처리와 내려갔을 때 뷰의 위치를 다시 되돌려 놓는 처리 그리고 지금 컨트롤이 키보드에 가려졌는지 안가려졌는지 확인을 위한 처리 구현
먼저 키보드가 컨트롤을 가렸는지 확인을 위해 변수 하나를 실수형으로 선언한다.
var fCurTextfieldBottom: CGFloat = 0.0
현재 포커싱된 컨트롤의 좌표를 구하기 위해 textFieldDidBeginEditing에서 현재 컨트롤의 y좌표와 해당 컨트롤의 높이를 더하면 나중에 키보드에 의해 가려졌는지 확인이 가능하므로 계산 후 일단 보관해둔다.
func textFieldDidBeginEditing(_ textField: UITextField) {
fCurTextfieldBottom = textField.frame.origin.y + textField.frame.height
}
이제 4번에서 등록한 selector함수인 키보드가 나타났을 때와 내려갔을 때 함수를 구현한다.
키보드의 사이즈(구조체)를 keyboardSize에 보관 후 현재뷰의 높이에서 빼주면 키보드가 잡아먹는 정확한 위치를 알 수 있다.
이를 앞서 계산해 보관해둔 fCurTextfieldBottom와 비교하여 fCurTextfieldBottom가 작거나 같으면 가려지지 않았으니 무시하고 크다면 1px이라도 가려졌으므로 현재 뷰를 키보드가 잡아먹는 높이만큼 올려주면 된다.
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if fCurTextfieldBottom <= self.view.frame.height - keyboardSize.height {
return
}
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
키보드가 사라졌을 땐 간단하다.
그냥 뷰가 이동됐으면 다시 원상복구해주고 아니면 아무런 처리를 하지 않는다.
@objc func keyboardWillHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
앞서 추가했던 done의 처리도 해주어 키보드가 내려가게끔 구현해준다.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
이렇게만 해두면 기본적인 처리는 다 되었고 만약 완료버튼(done) 대신 뷰의 아무곳이나 터치했을 때 키보드가 내려가길 원한다면
viewDidLoad에 제스쳐를 등록 후
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(endEditing)))
관련 함수를 구현해주면 깔끔하게 처리가 가능하겠다.
@objc func endEditing() {
txtTmp.resignFirstResponder()
txtId.resignFirstResponder()
txtPw.resignFirstResponder()
}
'모바일 & 앱' 카테고리의 다른 글
DIV print시 짤리지 않고 페이지 자동 넘기기 (print page auto cut) (0) | 2021.06.16 |
---|---|
Xcode 아이폰 연결 오류 : Errors were encountered while preparing your device for development. (0) | 2021.06.03 |
objective-c : 코드로 autolayout 추가하기 (0) | 2021.05.11 |
vue.js 기초 설치 (iMac 기준) (0) | 2021.05.04 |
javascript로 encode된 문자열 classic asp에서 decode시키기 (0) | 2021.04.01 |