키보드가 나타날 때, reviewTitleTextField가 가려지는 경우
→ 뷰 전체를 키보드 높이만큼 올렸다가, 키보드가 사라지면 원래 위치로 복귀하도록 처리해야 합니다.
✈️ 전체 코드
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupKeyboardNotifications()
}
private func setupKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc private func keyboardWillShow(_ notification: Notification) {
guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardHeight = keyboardFrame.cgRectValue.height
let textFieldBottom = textField.frame.origin.y + textField.frame.height
let keyboardTop = UIScreen.main.bounds.height - keyboardHeight
if textFieldBottom > keyboardTop {
let offset = textFieldBottom - keyboardTop + 20 // 키보드 위로 20pt 여유
UIView.animate(withDuration: 0.3) {
self.view.frame.origin.y -= offset
}
}
}
@objc private func keyboardWillHide(_ notification: Notification) {
UIView.animate(withDuration: 0.3) {
self.view.frame.origin.y = 0 // 원래 위치로 복귀
}
}
}
🚜 setupKeyboardNotifications() 구현
private func setupKeyboardNotifications() {
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(_:) 호출
- 키보드가 사라질 때 → keyboardWillHide(_:) 호출
🚋 키보드가 나타날 때 뷰를 올리기
@objc private func keyboardWillShow(_ notification: Notification) {
guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardHeight = keyboardFrame.cgRectValue.height
let textFieldBottom = textField.frame.origin.y + textField.frame.height
let keyboardTop = UIScreen.main.bounds.height - keyboardHeight
if textFieldBottom > keyboardTop {
let offset = textFieldBottom - keyboardTop + 20 // 키보드 위로 20pt 여유
UIView.animate(withDuration: 0.3) {
self.view.frame.origin.y -= offset
}
}
}
✅ 설명
- 키보드의 높이를 구함
- reviewTitleTextField의 바닥 위치를 계산
- reviewTitleTextField가 키보드에 가려지는지 확인
- 가려진다면, contentView를 키보드 높이만큼 위로 올림
🛵 키보드가 사라질 때 뷰 원위치로 복귀
@objc private func keyboardWillHide(_ notification: Notification) {
UIView.animate(withDuration: 0.3) {
self.contentView.frame.origin.y = 0 // 원래 위치로 복귀
}
}
✅ 설명
- 키보드가 사라지면 contentView를 원래 위치로 복귀
- 애니메이션 효과 적용하여 부드럽게 이동
🚗 문제 발생
moveViewForKeyboard(up:) 메서드에서 view.frame.origin.y를 직접 조정하는 방식의 문제
- view.frame.origin.y를 직접 변경하면 애니메이션 충돌 가능성이 있음.
- 키보드가 여러 번 올라오거나 사라질 때 뷰가 여러 번 이동할 가능성이 있음.
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupKeyboardNotifications()
textField.backgroundColor = .systemMint
textView.backgroundColor = .systemCyan
view.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(didTapView)))
//textField.delegate = self
}
private func setupKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc private func didTapView() {
view.endEditing(true)
}
@objc private func keyboardWillShow(_ notification: Notification) {
moveViewForKeyboard(up: true)
}
@objc private func keyboardWillHide(_ notification: Notification) {
moveViewForKeyboard(up: false)
}
private func moveViewForKeyboard(up: Bool) {
let movement: CGFloat = up ? -150 : 150 // ✅ 키보드 크기에 맞춰 조정
UIView.animate(withDuration: 0.3, animations: {
self.view.frame.origin.y += movement
})
}
}
✅ 올바른 해결 방법
👉 키보드 크기(keyboardFrame.height)를 정확하게 계산하여 뷰를 이동하도록 수정
👉 뷰의 현재 위치를 저장하고, 여러 번 이동하는 것을 방지
👉 UITextFieldDelegate에서 직접 뷰를 이동하지 않고, 키보드 알림(Notification)만 사용
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var textField: UITextField!
// 🚜 원래 뷰의 Y의 위치 저장
private var originalViewY: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
setupKeyboardNotifications()
textField.backgroundColor = .systemMint
textView.backgroundColor = .systemCyan
view.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(didTapView)))
// 🚜 현재 위치 저장
originalViewY = view.frame.origin.y
}
private func setupKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc private func didTapView() {
view.endEditing(true)
}
@objc private func keyboardWillShow(_ notification: Notification) {
guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardHeight = keyboardFrame.cgRectValue.height
let textFieldBottom = textField.frame.origin.y + textField.frame.height
let keyboardTop = UIScreen.main.bounds.height - keyboardHeight
if textFieldBottom > keyboardTop {
let offset = textFieldBottom - keyboardTop + 20
UIView.animate(withDuration: 0.3) {
self.view.frame.origin.y = self.originalViewY - offset
}
}
}
@objc private func keyboardWillHide(_ notification: Notification) {
UIView.animate(withDuration: 0.3) {
self.view.frame.origin.y = self.originalViewY // ✅ 원래 위치로 복귀
}
}
}
✅ 텍스트 필드와 텍스트 뷰 모두 키보드에 가리지 않도록 처리하는 방법
📌 핵심 로직
- 현재 어떤 입력창(textField or textView)이 활성화되었는지 확인
- 해당 입력창이 키보드에 가려질 경우 자동으로 이동
- 키보드가 사라지면 원래 위치로 복귀
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var textField: UITextField!
private var activeTextInput: UIView? // ✅ 현재 활성화된 입력창 (UITextField or UITextView)
private var originalViewY: CGFloat = 0 // ✅ 원래 뷰의 Y 위치 저장
override func viewDidLoad() {
super.viewDidLoad()
setupKeyboardNotifications()
textField.backgroundColor = .systemMint
textView.backgroundColor = .systemCyan
originalViewY = view.frame.origin.y // ✅ 원래 위치 저장
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapView))
view.addGestureRecognizer(tapGesture)
// ✅ 델리게이트 설정
textField.delegate = self
textView.delegate = self
}
private func setupKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc private func didTapView() {
view.endEditing(true) // ✅ 키보드 내리기
}
// 🚕 핵심 코드 부분
@objc private func keyboardWillShow(_ notification: Notification) {
guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardHeight = keyboardFrame.cgRectValue.height
guard let activeInput = activeTextInput else { return } // ✅ 현재 활성화된 입력창 확인
let inputBottom = activeInput.frame.origin.y + activeInput.frame.height
let keyboardTop = UIScreen.main.bounds.height - keyboardHeight
// 🚕 핵심 코드 부분
if inputBottom > keyboardTop {
let offset = inputBottom - keyboardTop + 20 // ✅ 키보드 위로 20pt 여유
UIView.animate(withDuration: 0.3) {
self.view.frame.origin.y = self.originalViewY - offset
}
}
}
@objc private func keyboardWillHide(_ notification: Notification) {
UIView.animate(withDuration: 0.3) {
self.view.frame.origin.y = self.originalViewY // ✅ 원래 위치로 복귀
}
}
}
// ✅ UITextFieldDelegate
extension ViewController: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
activeTextInput = textField // ✅ 현재 활성화된 입력창 저장
}
func textFieldDidEndEditing(_ textField: UITextField) {
activeTextInput = nil
}
}
// ✅ UITextViewDelegate
extension ViewController: UITextViewDelegate {
func textViewDidBeginEditing(_ textView: UITextView) {
activeTextInput = textView // ✅ 현재 활성화된 입력창 저장
}
func textViewDidEndEditing(_ textView: UITextView) {
activeTextInput = nil
}
}