Swift - 키보드의 높이를 알아내는 법🚀
앱 개발 중 TextField 또는 TextEditor와 같이 텍스트 입력 필드를 사용할 때, 자연스럽게 키보드가 화면 위로 올라오게 됩니다.
키보드가 올라온 화면까지 고려해서 디자인과 기능을 구현하기도 하고 또 구현 의도에 따라 키보드가 화면을 가리지 않도록 적절한 처리가 필요한 경우가 있습니다. 이를 위해 키보드의 높이를 감지하는 방법을 알아봅시다.
1️⃣ NotificationCenter를 사용하여 키보드 높이 구하기
📌 키보드 이벤트 감지하기
키보드의 높이를 알아내기 위해서는 키보드가 나타나거나 사라질 때 발생하는 Notification을 활용할 수 있습니다. iOS에서는 다음과 같은 키보드 관련 Notification을 제공합니다.
✅ UIKeyboardWillShowNotification : 키보드가 나타날 때 발생
✅ UIKeyboardWillHideNotification : 키보드가 사라질 때 발생
✅ UIKeyboardWillChangeFrameNotification : 키보드의 프레임이 변경될 때 발생
이 이벤트들을 활용하면 키보드의 상태 변화를 실시간으로 감지할 수 있습니다.
🎯 Notification에서 키보드 높이 가져오기
키보드 높이는 Notification에서 제공하는 userInfo 딕셔너리를 통해 확인할 수 있습니다.
UIKeyboardFrameEndUserInfoKey 키를 사용하여 최종 프레임 값을 가져오면, 키보드의 높이를 쉽게 얻을 수 있어요.
guard let keyboardInfo = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardSize = keyboardInfo.cgRectValue.size
let keyboardHeight = keyboardSize.height // Keyboard 높이
📌 키보드 높이 활용하기
키보드의 높이를 알게 되면, 키보드의 유무에 따른 화면의 변화를 자유롭게 만들 수 있습니다. 예를 들어, 입력 필드가 화면 하단에 위치할 경우 키보드의 높이만큼 여백을 증가시켜 뷰를 올리는 방식을 적용할 수 있습니다.
🎯 키보드가 사라질 때의 처리
키보드가 사라지면, 뷰의 위치를 원래 상태로 되돌려야 한다. 이를 위해 UIKeyboardWillHideNotification을 감지하여 뷰를 초기 위치로 복원하면 됩니다.
‼️주의
NotificationCenter를 사용할 때 removeObserver를 호출해주지 않으면 메모리에 남아있게 되니 주의해야 합니다.
- KeyboardObserver 전체 코드
import SwiftUI
class KeyboardObserver: ObservableObject {
private var notificationCenter: NotificationCenter
@Published var isShowing = false
@Published var height: CGFloat = 0
init(center: NotificationCenter = .default) {
notificationCenter = center
addObserver()
}
deinit {
removeObserver()
}
func addObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func removeObserver() {
NotificationCenter.default.removeObserver(self,name: UIResponder.keyboardWillShowNotification,object: nil)
NotificationCenter.default.removeObserver(self,name: UIResponder.keyboardWillHideNotification,object: nil)
}
@objc func keyboardWillShow(_ notification: Notification) {
isShowing = true
guard let userInfo = notification.userInfo as? [String: Any] else {
return
}
guard let keyboardInfo = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardSize = keyboardInfo.cgRectValue.size
height = keyboardSize.height
}
@objc func keyboardWillHide(_ notification: Notification) {
isShowing = false
height = 0
}
}
- 사용하는 View에서의 예시
import SwiftUI
struct ContentView: View {
@StateObject var keyboard: KeyboardObserver = KeyboardObserver()
var body: some View {
VStack {
...
Spacer()
.frame(height: keyboard.isShowing ? keyboard.height : 0)
}
}
}
2️⃣ Combine 사용하기
사실 위의 방법과 원리는 똑같습니다. 키보드 관련 Notification을 통해 상태를 확인하고, UIKeyboardFrameEndUserInfoKey 키를 통해 키보드의 Size와 높이를 알아낼 수 있습니다.
import SwiftUI
import Combine
class KeyboardObserver: ObservableObject {
@Published var isShowing = false
@Published var height: CGFloat = 0
private var cancellable = Set<AnyCancellable>()
init() {
bindKeyboardPublisher()
}
private func bindKeyboardPublisher() {
let keyboardWillShowPublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)
.map { notification -> CGFloat in
guard let userInfo = notification.userInfo as? [String: Any] else {
return .zero
}
guard let keyboardInfo = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return .zero
}
let keyboardSize = keyboardInfo.cgRectValue.size
return keyboardSize.height
}
let keyboardWillHidePublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat(0) }
Publishers.Merge(keyboardWillShowPublisher, keyboardWillHidePublisher)
.receive(on: RunLoop.main)
.sink { [weak self] height in
self?.height = height
self?.isShowing = height > 0
}
.store(in: &cancellable)
}
}
개인의 스타일에 따라 작성 방법의 차이인 것 같습니다!