[UIKit] 텍스트필드 입력(클릭) 시 키보드 올리기/내리기

2022. 8. 6. 18:32SWIFT/UIKit

728x90
반응형

🧸 시작

텍스트필드를 사용할 때 키보드가 위로 올라왔다가 내려갔다가 한다.

키보드가 올라가면서 화면을 가리게 되는 데 입력하는 텍스트필드가 가려질 때가 있다.

그러면 화면에 있는 컴포넌트들도 위로 올라가야한다. 이를 해결하기 위한 방법이다.

적용 전 적용 후

 

 

 

🧸 키보드 옵저버를 생성한다.

func keyboardObserver() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWhillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

func keyboardObserverRemove() {
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWhillShow(notification: NSNotification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
	//키보드가 올라올 때 실행
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
	//키보드가 내려갈 때 실행
    }
}

 

옵저버를 실행은 화면이 나타날 때 실행해주고 제거는 화면이 사라질 때 해주었다.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    keyboardObserver()
}

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

 

 

🧸 키보드의 사이즈만큼 화면을 올려준다.

1. 키보드의 높이를 구한다.

let keyboardHeight = keyboardFrame.cgRectValue.height

 

2. 화면의 safeArea 를 구한다.

let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
let windowBottom = window?.safeAreaInsets.bottom

 화면의 safeArea를 구하는 이유는 핸드폰 기종마다 높이가 달라지기 때문에 이렇게 해주는 것이 모든 기종의 키보드의 길이를 조정할 수 있었다.

 

3. 화면을 올려준다.

올리고 싶은 UIView의 Bottom Constraint를 IBOutlet으로 선언해준다.

코드로 할 경우는 변수로 지정해준다.

선언한 IBOutlet을 Bottom Constraint와 연결시킨다.

우리가 하고 싶은 건 키보드가 올라갔을 때 해당 제약조건이 위로 올라가는 것을 원하는 것이므로

키보드가 올라갔을 때의 제약조건의 값을 키보드의 값만큼 더해주면 된다.

if self.viewBottomConstraint.constant == 0{
   self.viewBottomConstraint.constant += (keyboardHeight-(windowBottom ?? 0))
}

제약조건이 0일 때가 바닥에 붙어있을 경우니까 그 때 키보드의 높이만큼 더해준다.

키보드높이에서 윈도우의 높이를 빼준 것은 키보드의 높이에는 safeArea가 포함되어있기 때문에 내가 원하는 만큼의 높이보다 더 올라가게 된다.

이 부분은 자신이 원하는 높이를 정해서 올려주면 된다.

 

 

✔️ 주의사항

여기서 주의사항은 view안에 있는 입력창의 제약조건이다.

입력창의 제약조건이 view의 bottom과 연관이 있어야한다. 

해당 화면처럼 입력창 bottom의 제약조건이 view의 bottom에서 떨어져있는 형태이다.

그래야 view의 bottom 제약조건을 변경했을 때 하위의 컴포넌트들의 위치가 변화된다.

만약에 이렇게 하지않고 top에 제약조건을 두고 

이렇게 구현한다면 키보드 옵저버를 잘 구현했더라도 입력창의 위치는 변화하지 않는다.

제약조건을 잘 확인해야한다!

 

그리고 위에서 화면의 safeArea를 구하는 이유는

만약에 화면의 safeArea를 구해서 빼주지 않으면 아래 화면처럼 흰색의 공간이 생긴다.



맥북을 외부 키보드와 연결한 경우에는 키보드가 보이지 않을 때가 있다.

이럴 경우에는 물리적인 키보드를 꺼줘야한다.

connect Hardware Keyboard를 꺼준다.

이게 켜져있다면 키보드를 2개인식할 경우도 있기도 하다. 그냥 꺼주는 것이 좋다.

 

 

 

🧸 키보드의 사이즈만큼 화면을 내려준다.

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
        //키보드가 내려갈 때 실행
        let keyboardHeight = keyboardFrame.cgRectValue.height
        let scenes = UIApplication.shared.connectedScenes
        let windowScene = scenes.first as? UIWindowScene
        let window = windowScene?.windows.first
        let windowBottom = window?.safeAreaInsets.bottom
        UIView.animate(withDuration: 1) {
            if self.viewBottomConstraint.constant == 0 {
               self.viewBottomConstraint.constant -= (keyboardHeight-(windowBottom ?? 0))
           }
        }
    }
}

이번에는 키보드를 내려줄 때의 코드이다.

올려줄 때와 반대로 키보드의 높이만큼 다시 빼주면 된다.

UIView.animate(withDuration: 1) {

animate를 이용하여 조금 더 부드럽게 화면이 이동할 수 있게 했다.

 

 

🧸 빈 배경을 클릭했을 때 키보드가 내려가게 하는 방법

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.view.endEditing(true)
}

오버라이드한 함수이므로 따로 호출하지 않아도 된다.

 

 

 

 


📂 정리

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var viewBottomConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        keyboardObserver()
    }

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

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }
    
    func keyboardObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWhillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    func keyboardObserverRemove() {
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    @objc func keyboardWhillShow(notification: NSNotification) {
        if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
            //키보드가 올라올 때 실행
            let keyboardHeight = keyboardFrame.cgRectValue.height
            let scenes = UIApplication.shared.connectedScenes
            let windowScene = scenes.first as? UIWindowScene
            let window = windowScene?.windows.first
            let windowBottom = window?.safeAreaInsets.bottom
            UIView.animate(withDuration: 1) {
                if self.viewBottomConstraint.constant == 0 {
                   self.viewBottomConstraint.constant += (keyboardHeight-(windowBottom ?? 0))
               }
            }
        }
    }

    @objc func keyboardWillHide(notification: NSNotification) {
        if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
            //키보드가 내려갈 때 실행
            let keyboardHeight = keyboardFrame.cgRectValue.height
            let scenes = UIApplication.shared.connectedScenes
            let windowScene = scenes.first as? UIWindowScene
            let window = windowScene?.windows.first
            let windowBottom = window?.safeAreaInsets.bottom
            UIView.animate(withDuration: 1) {
               self.viewBottomConstraint.constant -= (keyboardHeight-(windowBottom ?? 0))
            }
        }
    }
}

스토리보드는 이렇게만 되어있고 위에서 언급했듯이 입력창의 제약조건만 잘 설정해주면 구현할 수 있다.

 

 

 

 

 

 

 

 

 

 

[예제 소스코드 깃허브 링크]

https://github.com/HANLeeeee/PracticeTest/tree/main/KeyboardTest

 

GitHub - HANLeeeee/PracticeTest

Contribute to HANLeeeee/PracticeTest development by creating an account on GitHub.

github.com

 

 

 

 

 

728x90
반응형