Post

UIKit - NotificationCenter를 활용하여 키보드 높이만큼 View 올리기, 내리기

View에 여러 개의 UITextField를 배치하게 되면 키보드가 올라왔을 때 가려지는 현상이 발생하게 됨.

이런 문제를 NotificationCenter를 통해 키보드가 올라왔을 때, 내려왔을 때를 감지하여 View를 올려줌으로써 해결할 수 있음.

내 경우에는 닉네임을 입력하는 UITextFieldfirstResponder가 됬을 때만 View가 올라가도록 하고, 나머지는 그대로 유지하도록 처리함.

키보드 여부, 기존 origin 값의 상태 관리를 위해 Model을 하나 정의해줌.

RegisterViewManager.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import Foundation

final class RegisterViewManager{
    
    public static let shared = RegisterViewManager()
    
    private init() {}
    
    // 키보드 여부
    private var isKeyboard: Bool = false
    
    // 기존 origin Y 값
    private var originY: CGFloat?
    
    func setIsKeyboard(_ value: Bool){
        self.isKeyboard = value
    }
    
    func getIsKeyboard() -> Bool{
        return self.isKeyboard
    }
    
    func setOriginY(_ value: CGFloat?){
        self.originY = value
    }
    
    func getOriginY() -> CGFloat?{
        return self.originY
    }
}

RegisterViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import UIKit

final class RegisterViewController: UIViewController {
    
    private let registerView = RegisterView()
    
    private let registerViewManager = RegisterViewManager.shared
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // NotificationCenter Observe 설정
        setKeyboardObserver()

        // origin Y축 값 설정
        registerViewManager.setOriginY(self.view.frame.origin.y)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // 설정된 NotificationCenter Observe 해제
        removeKeyboardObserver()
    }
}

// MARK: - Notification Center
extension RegisterViewController{
    
    func setKeyboardObserver(){
      // 키보드가 올라오기 전에 처리할 핸들러 등록
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
        
      // 키보드가 내려가기 전에 처리할 핸들러 등록
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    func removeKeyboardObserver(){
      // deinit 시점에 설정한 핸들러 제거

        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
      
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    @objc func keyboardWillShow(notification: NSNotification){
        
        // 닉네임 TextField가 firstResponder일 경우
        if registerView.getNicknameTextField().isFirstResponder{
            
            // 키보드가 올라와있다면 return
            guard !registerViewManager.getIsKeyboard() else { return }
            
            // 키보드 높이 구하기
            if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue{
                let keyboardRectangle = keyboardFrame.cgRectValue
                let keyboardHeight = keyboardRectangle.height
                
                // View 올리기
                UIView.animate(withDuration: 0.5) {
                    self.view.frame.origin.y -= keyboardHeight
                }
                
                // isKeyboard 프로퍼티 true 설정
                registerViewManager.setIsKeyboard(true)
            }
        }else{
            // 만약 닉네임 TextField가 아닌 다른 TextField 요소가 firstResponder가 됬을 때 실행

            // 기존 origin 값과 현재 origin 값이 같지 않다면
            if self.view.frame.origin.y != registerViewManager.getOriginY(){
                
                // 키보드 높이를 구한 후 View를 내려줌
                if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue{
                    let keyboardRectangle = keyboardFrame.cgRectValue
                    let keyboardHeight = keyboardRectangle.height
                    
                    UIView.animate(withDuration: 0.5) {
                        self.view.frame.origin.y += keyboardHeight
                    }
                    
                    registerViewManager.setIsKeyboard(false)
                    registerViewManager.setOriginY(self.view.frame.origin.y)
                }
                
            }
        }
    }
    
    @objc func keyboardWillHide(notification: NSNotification){
      // 닉네임 TextField가 firstResponder라면 실행
        if registerView.getNicknameTextField().isFirstResponder{
            
            guard registerViewManager.getIsKeyboard() else { return }
            
            // 키보드 높이를 구한 뒤 View를 내려줌
            if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue{
                let keyboardRectangle = keyboardFrame.cgRectValue
                let keyboardHeight = keyboardRectangle.height
                
                UIView.animate(withDuration: 0.5) {
                    self.view.frame.origin.y += keyboardHeight
                }
                
                registerViewManager.setIsKeyboard(false)
            }
        }
    }   
}

결과

image

This post is licensed under CC BY 4.0 by the author.