키보드를 보이게 하는데에 다양한 방법이 있다.
내가 시도해본 방법으로는
- view 의 frame 을 변경하는 방법
- view 의 autolayout 을 변경하는 방법
- view 의 contentInset 을 변경하는 방법
- keyBoard autolayout 활용하기 (iOS15 부터 가능)
들이 있다. 하나 하나 시도를 해보자.
우선 1~3 3가지 방법은 아주 약간만 다르고 방법이 비슷하다.
4번은 새로나온 아주 쉬운 방법이다.
1~3 방법을 먼저 구현해보자
⌨️ 키보드 내리기
우선 일반적인 앱은 textFied 나 textView 가 아닌 곳을 터치하면 입력이 끝났다고 생각하고 키보드가 내려간다. 이것을 구현해보자.
ViewController 에 아래 두가지 메서드를 구현한다.
private func setViewGesture() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(keyboardDownAction))
view.addGestureRecognizer(tapGesture)
}
@objc func keyboardDownAction(_ sender: UISwipeGestureRecognizer) {
self.view.endEditing(true) // 이거하면 키보드가 내려감
}
setViewGesture 에서는 탭하는 제스처를 하면 keyboardDownAction 메서드가 실행되도록 하는 로직이다.
keyboardDownAction 이 호출되면 view 가 수정이 끝났다는 것을 알려주기 때문에 키보드가 내려간다.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setViewGesture()
}
}
⌨️ Notification 등록하기
키보드가 나타나면 뷰를 키보드에 높이에 따라 어떤 방법으로든 수정을 해주어야 한다. 그럴려면 키보드의 높이! 를 구해와야 한다.
키보드의 높이는 Notification 을 통해 구할 수가 있다.
private func registerForKeyboardNotification() {
NotificationCenter.default.addObserver(self,
selector: #selector(keyBoardShow),
name: UIResponder.keyboardWillShowNotification,
object: nil)
}
Notification 의 name 에 UIResponder.keyboardWillShowNotification 을 넣으면 키보드가 나타날 때 마다 Noti 를 받겠다는 뜻이다.
@objc private func keyBoardShow(notification: NSNotification) {
// Noti 를 받아서 키보드의 높이를 가져오기
guard let userInfo: NSDictionary = notification.userInfo as? NSDictionary else {
return
}
guard let keyboardFrame = userInfo.value(forKey: UIResponder.keyboardFrameEndUserInfoKey) as? NSValue else {
return
}
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
}
키보드가 나타나면 키보드의 높이를 구해줄 메서드를 실행하면 된다.
(높이를 구해서 어떻게 할지는 좀 더 아래 나온다.)
viewDidLoad 에서 노티 등록 메서드를 호출해 주면 된다!
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setViewGesture()
registerForKeyboardNotification()
}
}
노티는 등록을 해줬으니 뷰 이동할 떄는 해제를 하는 것이 좋다.
private func removeRegisterForKeyboardNotification() {
NotificationCenter.default.removeObserver(self,
name: UIResponder.keyboardWillShowNotification,
object: nil)
}
해제해 주는 메서드를 만들고 그걸 viewWillDisappear 나 viewDidDisappear 에 추가해 주자!
이제 키보드의 높이를 구했으니 이걸로 뷰를 움직여 보자!
⚙️ view 의 frame 을 변경하는 방법
@objc private func keyBoardShow(notification: NSNotification) {
// Noti 를 받아서 키보드의 높이를 가져오기
guard let userInfo: NSDictionary = notification.userInfo as? NSDictionary else {
return
}
guard let keyboardFrame = userInfo.value(forKey: UIResponder.keyboardFrameEndUserInfoKey) as? NSValue else {
return
}
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
// 이 부분 추가
// view 의 프레임 이동
view.frame.origin.y -= keyboardHeight
}
@objc func keyboardDownAction(_ sender: UISwipeGestureRecognizer) {
self.view.endEditing(true) // 이거하면 키보드가 내려감
// 다시 view의 frame을 되돌려 놓기
view.frame.origin.y = 0
}
키보드가 올라갈 때 호출되는 메서드에 frame 을 이동시키고 키보드가 내려갈 때 다시 되돌려 놓으면 된다!
(내려올 때 애니메이션이 뭔가 자연스러운것 같지는 않지만...어떻게 자연스럽게 하면되는지 아시는분...?)
채팅앱 같은 곳에서 사용하는 방식이 아마 이런 느낌인 것 같다.
⚙️ view 의 frame 을 변경하는 방법
view 의 autolayout 을 변경하는 방법
우선 예시에서는 skyTextView 의 bottom 제약 이외의 제약들은 스토리보드로 주었다.
코드로 주어도 상관없다.
class TextViewController: UIViewController {
@IBOutlet var skyTextView: UITextView!
private lazy var textViewBottomConstraint = skyTextView.bottomAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.bottomAnchor
)
func setConstraint() {
textViewBottomConstraint.isActive = true
}
func changeTextViewBottomAutoLayout(_ keyboardHeight: CGFloat = 0) {
textViewBottomConstraint.isActive = false
textViewBottomConstraint = skyTextView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -keyboardHeight)
textViewBottomConstraint.isActive = true
}
}
오토레이아웃을 제약 사항이 대체되는 것이 아니라 겹쳐서 생성 되기 때문에 사용하지 않는 제약을 꺼주어야 한다.
그래서 기본 제약을 끌 수 있게 textViewBottomConstraint 이라는 변수로 만들어 주었다.
changeTextViewBottomAutoLayout 이라는 메서드가 파라미터로 키보드 높이를 받아서 변경된 제약 사항을 적용해준다.
@objc private func keyBoardShow(notification: NSNotification) {
// Noti 를 받아서 키보드의 높이를 가져오기
guard let userInfo: NSDictionary = notification.userInfo as? NSDictionary else {
return
}
guard let keyboardFrame = userInfo.value(forKey: UIResponder.keyboardFrameEndUserInfoKey) as? NSValue else {
return
}
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
// 이 부분 추가
// view 의 BottomAutoLayout 변경
changeTextViewBottomAutoLayout(keyboardHeight)
}
@objc func keyboardDownAction(_ sender: UISwipeGestureRecognizer) {
self.view.endEditing(true) // 이거하면 키보드가 내려감
// view 의 BottomAutoLayout 원래대로
changeTextViewBottomAutoLayout()
}
changeTextViewBottomAutoLayout 을 키보드가 나타날 때 없어질 때 호출해주기만 하면 된다.
⚙️ view 의 contenInset 을 변경하는 방법
textView 는 자동으로 ScrollView 이다.
ContentInset 이라는 것은 Conten 뷰의 내부의 여백을 말한다.
글이 있는 부분 이외에 내부 공간 여백을 얼마나 둘 것인지로 생각하면 된다.
@objc private func keyBoardShow(notification: NSNotification) {
// Noti 를 받아서 키보드의 높이를 가져오기
guard let userInfo: NSDictionary = notification.userInfo as? NSDictionary else {
return
}
guard let keyboardFrame = userInfo.value(forKey: UIResponder.keyboardFrameEndUserInfoKey) as? NSValue else {
return
}
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
// 이 부분 추가
// view 의 ContentInset 수정
skyTextView.contentInset.bottom += keyboardHeight
}
@objc func keyboardDownAction(_ sender: UISwipeGestureRecognizer) {
self.view.endEditing(true) // 이거하면 키보드가 내려감
/// view 의 ContentInset 원래대로
skyTextView.contentInset.bottom = 0
}
⌨️ keyBoard autolayout 활용하기
iOS15 부터는 완전히 간단한 방법이 생겼다!
키보드 자체에 autolayout 이 생긴것이다!
키보드 높이를 가져오기 위해서 Notification 을 줄 일이 없는 것이다!
view.keyboardLayoutGuide.topAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true
이 한줄의 제약만 주면 끝!
애니메이션도 완전 자연스럽다. 알아서 잘 적용됨.
이걸 왜 iOS15 에 와서야 해주었을까!!
완전 대박!!
그래도 아직은 15만 지원할 수 없으니 위의 방법들도 써야 한다...
참고자료
WWDC
'🍎 iOS > 🍏 UIKit' 카테고리의 다른 글
인스타그램 스타일 Page Control (0) | 2023.07.04 |
---|---|
[UIKit] App life cycle 이란? (0) | 2023.01.27 |
[iOS]사용자의 폰트 사이즈 정보에 따라 UI 바꿔주기 (0) | 2023.01.06 |
[iOS] delegate 구현하기 (0) | 2023.01.06 |
[iOS] Notification Center 구현하기 (0) | 2023.01.06 |