iOS Swift/iOS Swift - 예제

[iOS/Swift] 키보드 화면 올리기 위에 버튼 감지 활성

주니어코더 2023. 6. 13. 18:27

 

 

 

 

 

 

⌨️ 키보드 화면 올리기 ⌨️

 

부제

키보드 위에 버튼 올리기 
키보드 감지 활성화

ios 화면 터치 시 키보드 내리기

 

 

 

어떻게 동작하는지 먼저 보자!

 

 

 

 

키보드가 나타나면

하단 버튼이 키보드 위로 올라가는 기능 구현

 

 

 

 

 

Chap1.  view 만들기 (UITextfield, UIButton 생성)


 

먼저 텍스트필드와 버튼을 포함한 뷰를 만든다!

 

Storyboard 가 아닌 코드로만 생성하였다

 

import UIKit

class ViewController: UIViewController {
    
    lazy var baseView: UIView = {
        var view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    lazy var titleLb: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "비밀번호를 입력해주세요"
        return label
    }()
    
    lazy var textfield: UITextField = {
        var view = UITextField()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.placeholder = "비밀번호를 입력해주세요"
        return view
    }()

    lazy var bottomButton: UIButton = {
        let button = UIButton(type: .system)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("다음", for: .normal)
        button.backgroundColor = .systemGray5
        button.setTitleColor(.white, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: .bold)
        return button
    }()
    
    // 하단 노치와 버튼 색상을 통일하는 뷰
    lazy var bottomBaseView: UIView = {
        var view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .systemGray5
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        title = "비밀먼호 재설정"
        view.backgroundColor = .white
        addViews()
        applyConstraints()
    }
    
    fileprivate func addViews() {
        view.addSubview(baseView)
        baseView.addSubview(titleLb)
        baseView.addSubview(textfield)
        baseView.addSubview(bottomButton)
        view.addSubview(bottomBaseView)
    }

    fileprivate func applyConstraints() {
        let baseViewConstraints = [
            baseView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            baseView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            baseView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            baseView.bottomAnchor.constraint(equalTo:  view.safeAreaLayoutGuide.bottomAnchor)
        ]
        
        let titleLbConstraints = [
            titleLb.leadingAnchor.constraint(equalTo: baseView.leadingAnchor, constant: 30),
            titleLb.topAnchor.constraint(equalTo: baseView.topAnchor, constant: 30),
        ]
        
        let textfieldConstraints = [
            textfield.leadingAnchor.constraint(equalTo: baseView.leadingAnchor, constant: 30),
            textfield.topAnchor.constraint(equalTo: titleLb.bottomAnchor, constant: 20),
        ]
        
        let bottomButtonConstraints = [
            bottomButton.leadingAnchor.constraint(equalTo: baseView.leadingAnchor),
            bottomButton.trailingAnchor.constraint(equalTo: baseView.trailingAnchor),
            bottomButton.bottomAnchor.constraint(equalTo: baseView.bottomAnchor),
            bottomButton.heightAnchor.constraint(equalToConstant: 50)
        ]
        
        let bottomBaseViewConstraints = [
            bottomBaseView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            bottomBaseView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            bottomBaseView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            bottomBaseView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ]
        
        NSLayoutConstraint.activate(baseViewConstraints)
        NSLayoutConstraint.activate(titleLbConstraints)
        NSLayoutConstraint.activate(textfieldConstraints)
        NSLayoutConstraint.activate(bottomButtonConstraints)
        NSLayoutConstraint.activate(bottomBaseViewConstraints)

    }
}

 

뷰를 간단히 설명하면

textfieldbutton 을 생성하여 view에 추가하고 constraint 설정

button의 constraint는 view.safeAreaLayoutGuide.bottom에 붙였다

 

 

 

 

 

Chap2.  Keyboard 의 움직임을 감지하는 Notification을 Observer 패턴으로 구독


🔎 notification 과 observer란?

✔️ Notificaion

Notification(노티피케이션)은 싱글턴 객체중 하나로 이벤트들의 발생 여부를 옵저버를 등록한 객체들에게 Notification을 post 하는 방식으로 사용한다.

Notification Name이란 Key값을 통해 보내고 받을 수 있다.

 

✔️ Observer

Observer(옵저버)은 특정 객체에서 발생하는 이벤트를 구독자에게 전달하는 패턴이다.

 

즉, 프로퍼티 옵저버란 단어 뜻대로 관찰자 역할을 한다.

개발자가 관찰하는 프로퍼티에 누가 값을 설정하려고 하면 변경 감지를 하면서 property 값이 변경되려고 한다고 알려주는 것이다.

 

 

아래는 Notification을 observer 패턴으로 구독하는 코드

 

    override func viewWillAppear(_ animated: Bool) {
        self.addKeyboardNotifications()
    }
    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardNotifications()
    }

	// 노티피케이션을 추가하는 메서드
    func addKeyboardNotifications(){
        // 키보드가 나타날 때 앱에게 알리는 메서드 추가
        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 removeKeyboardNotifications(){
        // 키보드가 나타날 때 앱에게 알리는 메서드 제거
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification , object: nil)
        // 키보드가 사라질 때 앱에게 알리는 메서드 제거
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    @objc func keyboardWillShow(_ noti: NSNotification){
        // 키보드가 나타날 때 코드

    }

    @objc func keyboardWillHide(_ noti: NSNotification){
        // 키보드가 사라졌을 때 코드
    }

 

📖 설명 ✏️

 

View가 생성될 때 작동하는 생명주기 viewWillAppear()에 노티피케이션을 추가하는 코드 작성

➡ 해당 View가 생성됐을 때, 키보드의 움직임을 감지하는 옵저버를 추가하는 코드를 작성

 

View가 사라질 때 작동하는 생명주기 viewWillDisappear()노티피케이션을 삭제하는 코드 작성
해당 View에서 사라질 때 키보드의 움직임을 감지하는 옵저버를 삭제하는 코드를 작성

 

 

원하는 뷰에서만 키보드의 움직임을 감지하기 위해 노티피케이션 구독을 생성할 때 추가, 사라질 때 삭제 한다!

 

 

 

 

 

Chap3.  keyboard 움직임을 감지하는 코드 작성


 

이젠 진짜로 keyboard 움직임을 감지하는 코드를 작성하자~

작동하는 원리를 살펴보자

 

 


bottomButton(다음 버튼)의bottomAnchor.constraint.const의 값을 변경하여 버튼의 높이 조절

bottomButtonConstraint = bottomButton.bottomAnchor.constraint 대입

 

키보드 활성 ❌ bottomButtonConstraint = 0

키보드 활성 ⭕️ bottomButtonConstraint = - keyboardHeight

 

 

 

위 설명을 코드로 구현하면 아래와 같다

 

    override func viewWillAppear(_ animated: Bool) {
        self.addKeyboardNotifications()
    }
    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardNotifications()
    }
    
    var bottomButtonConstraint: NSLayoutConstraint?
    
    // 노티피케이션을 추가하는 메서드
    func addKeyboardNotifications(){
        // 키보드가 나타날 때 앱에게 알리는 메서드 추가
        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 removeKeyboardNotifications(){
        // 키보드가 나타날 때 앱에게 알리는 메서드 제거
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification , object: nil)
        // 키보드가 사라질 때 앱에게 알리는 메서드 제거
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    @objc func keyboardWillShow(_ noti: NSNotification){
        // 키보드의 높이만큼 화면을 올려준다.
        if let keyboardFrame: NSValue = noti.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
            let keyboardRectangle = keyboardFrame.cgRectValue
            let keyboardHeight = keyboardRectangle.height
            //bottomBaseView의 높이를 올려준다
            // 노치 디자인이 있는 경우 safe area를 계산합니다.
            if #available(iOS 11.0, *) {
                let bottomInset = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.safeAreaInsets.bottom ?? 0
                let adjustedKeyboardHeight = keyboardHeight - bottomInset
                    // bottomBaseView의 높이를 올려준다
                bottomButtonConstraint?.constant = -adjustedKeyboardHeight
            } else {
                    // 노치 디자인이 없는 경우에는 원래대로 계산합니다.
                bottomButtonConstraint?.constant = -keyboardHeight
            }
            view.layoutIfNeeded()
        }
    }

    @objc func keyboardWillHide(_ noti: NSNotification){
        // 키보드의 높이만큼 화면을 내려준다.
        bottomButtonConstraint?.constant = 0
        view.layoutIfNeeded()
    }
    
    fileprivate func addViews() {
        view.addSubview(baseView)
        baseView.addSubview(titleLb)
        baseView.addSubview(textfield)
        baseView.addSubview(bottomButton)
        view.addSubview(bottomBaseView)
    }

    fileprivate func applyConstraints() {
        let baseViewConstraints = [
            baseView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            baseView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            baseView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            baseView.bottomAnchor.constraint(equalTo:  view.safeAreaLayoutGuide.bottomAnchor)
        ]
        
        let titleLbConstraints = [
            titleLb.leadingAnchor.constraint(equalTo: baseView.leadingAnchor, constant: 30),
            titleLb.topAnchor.constraint(equalTo: baseView.topAnchor, constant: 30),
        ]
        
        let textfieldConstraints = [
            textfield.leadingAnchor.constraint(equalTo: baseView.leadingAnchor, constant: 30),
            textfield.topAnchor.constraint(equalTo: titleLb.bottomAnchor, constant: 20),
        ]
        
        self.bottomButtonConstraint = bottomButton.bottomAnchor.constraint(equalTo: baseView.bottomAnchor)

        let bottomButtonConstraints = [
            bottomButton.leadingAnchor.constraint(equalTo: baseView.leadingAnchor),
            bottomButton.trailingAnchor.constraint(equalTo: baseView.trailingAnchor),
            bottomButtonConstraint!,
            bottomButton.heightAnchor.constraint(equalToConstant: 50)
        ]
        
        let bottomBaseViewConstraints = [
            bottomBaseView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            bottomBaseView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            bottomBaseView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            bottomBaseView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ]
        
        NSLayoutConstraint.activate(baseViewConstraints)
        NSLayoutConstraint.activate(titleLbConstraints)
        NSLayoutConstraint.activate(textfieldConstraints)
        NSLayoutConstraint.activate(bottomButtonConstraints)
        NSLayoutConstraint.activate(bottomBaseViewConstraints)

    }

 

🚫 주의 🚫

노치가 있는 디자인의 경우 하단 노치 높이인 safe area의 bottomInset 만큼을 더 높여준다

 

 

 

 

 

Chap4. 화면 터치 시 키보드 내리기


 

iOS에서 화면 터치 시 키보드 내리기는 매우 간단!

 

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

 

view를 클릭하였을 때 수정이 끝나 키보드를 내리는 코드다

 

 

 

 

 

 

결과

 

 

 

 

 

 

 

후기

 

한번 알아두면 두고두고 사용할사골 같은 코드..⭐️

제대로 알고 넘어가자

 

 

 

 

 

 

 

 

 👇 깃허브에서 전체 소스코드 보기 👇

https://github.com/hyeebin/ex-keyboard-ios

 

GitHub - hyeebin/ex-keyboard-ios: iOS dynamic keyboard example

iOS dynamic keyboard example. Contribute to hyeebin/ex-keyboard-ios development by creating an account on GitHub.

github.com

 

반응형