프로젝트를 진행하면서 키보드가 텍스트뷰를 가리지 않도록 하는 기능을 구현할 때가 가끔있는데,
저번 프로젝트는 이해를 제대로 못하고 썼었는데, 이번 프로젝트때 제대로 알고 쓰기 위해 정리하려고 한다.
이렇게 2가지 상황에서 Notification Center를 사용해볼거다 🤓
공식문서 먼저 보는 습관..
정의를 보면
Notification은 등록된 관찰자에게 정보를 브로드캐스트할 수 있는 알림 발송 메커니즘이다
라고 되어 있는데,
여기서 포인트는
- 등록된 관찰자에게 (addObserver)
- 정보를 브로드캐스트 (post)
한다는 것이다.
어떤 이벤트에 대한 알림을 받기를 원하는 관찰자를 추가하면,
그 이벤트가 발생하면 알려주는 메커니즘 이라는 것 같다.
계속 공식문서를 읽어보면,
addObserver()
메서드를 통해 객체를 알림센터에 관찰자로 등록할 수 있다.
객체가 관찰자로 자신을 추가할 때, 수신해야 할 알림을 지정한다.
객체는 여러 다른 알림에 대한 관찰자로 등록하기 위해,addObserver()
메서드를 여러번 호출할 수 있다.
실행 중인 각 앱에는 기본 알림 센터가 있으며, 새 알림 센터를 만들 수도 있다.
그러니까 한 객체가 여러 알림을 받을 수도 있는 듯 하다!
키보드가 텍스트뷰를 가리지 않도록 하는 기능을 구현하기 위해 먼저 아래와 같이 가이드라인을 잡았다.
1️⃣ Observer를 추가해준다
2️⃣ 어떤 이벤트가 발생했을 때 그 Observer에게 알림을 발송한다
3️⃣ 알림을 받으면 텍스트뷰를 키보드 높이만큼 줄이거나, 원래 크기로 늘이기
NotificationCenter의 타입프로퍼티로 default가 있는데, 공식문서에서 말했던 기본 알림센터인것 같다.
이걸 써서 기본 알림센터에 Observer를 추가해준다.
private func addKeyboardObserver() {
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide),
name: UIResponder.keyboardWillHideNotification,
object: nil)
}
addObserver
메서드에는 파라미터가 4개나 있는데, 하나씩 살펴보자면
요렇게 된다.
텍스트뷰를 클릭하면 키보드가 올라오는데,
키보드가 올라오기 직전에 keyboardWillShowNotification이라는 이름의 Notification이 post되고
그러면 Observer로 등록한 뷰가 그 Notification을 받아서 #selector의 메서드를 실행하는 프로세스인 것 같다.
그럼 알림을 받았을 때 실행하는 keyboardWillShow와 keyboardWillHide에서는 어떤일이 벌어질까?!
keyboardWillShow에서는
1) userInfo (Notification과 관련된 값(keyboard)의 정보가 들어있는 딕셔너리 형태의 저장소)를 사용해서 키보드의 높이를 구함
2) textView의 height를 키보드의 높이만큼 줄임
keyboardWillHide에서는
1) 다시 textView의 height를 원래대로 늘임
이렇게 구현해보았다.
@objc private func keyboardWillShow(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
return
}
let contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardFrame.height, right: 0.0)
diaryTextView.contentInset = contentInset
diaryTextView.scrollIndicatorInsets = contentInset
}
@objc private func keyboardWillHide() {
let contentInset = UIEdgeInsets.zero
diaryTextView.contentInset = contentInset
diaryTextView.scrollIndicatorInsets = contentInset
}
여기서 키보드의 프레임을 구할 때 사용되는 keyboardFrameEndUserInfoKey는
"A user info key to retrieve the keyboard’s frame at the end of its animation."
애니메이션 마지막에 키보드의 프레임을 반환하는 user info key라고 한다.
그래서 이걸 key로 userInfo에서 키보드의 프레임을 구하는 것 같다!
1️⃣ Observer를 추가해준다
2️⃣ 어떤 이벤트가 발생했을 때 그 Observer에게 알림을 발송한다
키보드 했을 때랑 똑같이 addObserver를 해준다.
NotificationCenter.default.addObserver(self,
selector: #selector(saveDiary),
name: Notification.Name.sceneDidEnterBackgroundNotification,
object: nil)
(sceneDidEnterBackgroundNotification은 Notification.Name을 extension해서 만들어줬다)
그리고 알림을 발송하는 시점 == 앱이 백그라운드에 진입하는 시점이기 때문에
SceneDelegate의 sceneDidEnterBackground(_ scene: UIScene)
메서드에서 post를 해준다.
NotificationCenter.default.post(name: Notification.Name.sceneDidEnterBackgroundNotification,
object: nil)
이러면 observer에서 알림을 수신했을때 #selector의 saveDiary를 실행해서 데이터를 저장할 수 있다!😎
참고자료