2017년 3월 28일 화요일

iOS & Swift : Keyboard가 표시될 때, 사라질 때 이벤트와 그 키보드의 위치를 알아보자

지난 블로그에서는 Objective-C를 기준으로 정리하였는데, 이제는 Swift를 기준으로 정리한다.
(링크 [iOS] Keyboard가 표시될 때, 사라질 때 이벤트와 그 키보드의 위치는?)

일반적인 UIViewController 내에서는 표시할 위치를 이동시켜야, 키보드에 덮히지 않고, 사용자에게 표시할 수 있습니다.

1. 키보드가 화면에 나타나거나, 사라지는 Event는 무엇이고, 어떻게 알아낼까?

키보드가 표시될 때 전달되는 이벤트는...
  • NSNotification.Name.UIKeyboardWillShow : 키보드가 표시되기 전에 호출
  • NSNotification.Name.UIKeyboardDidShow : 키보드가 표시되고 난 후에 호출
  • NSNotification.Name.UIKeyboardWillHide : 키보드를 숨기기 전에 호출
  • NSNotification.Name.UIKeyboardDidHide : 키보드를 숨기고 난 후에 호출
  • NSNotification.Name.UIKeyboardWillChangeFrame : 키보드 모양이 바뀌기 전 (iOS 5 이상)
  • NSNotification.Name.UIKeyboardDidChangeFrame : 키보드 모양이 바뀐 후 (iOS 5 이상)
필요한 이벤트를 viewWillAppear 함수에서 NotificationCenter에 등록합니다.
Source Code
    override func viewWillAppear(_ animated: Bool) {
        //화면이 표시될때, Keyboard표시에 대한 이벤트가 발생하면 호출되는 함수를 등록한다.
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardDidShow(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardDidHide(_:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
    }

화면이 사라질 때, 등록한 것을 삭제해야 한다. 물론 삭제하면 더 이상 이벤트가 발생해도 해당 함수를 호출하지 않습니다.

SourceCode
    override func viewWillDisappear(_ animated: Bool) {
        //화면이 사라질 때, keyboard 표시에 대한 이벤트를 받지 않도록, 등록을 삭제한다.
        NotificationCenter.default.removeObserver(self)
    }


이벤트가 발생할 때, 호출하는 함수들을 정의한다. 해당 이름은 뭐든지 관계없으나 인자로 받는 것은 명시를 해줘야 합니다.

SourceCode
    //키보드가 표시 될 때 호출 되는 함수
    func keyboardWillShow(_ notification:NSNotification) {
        print(notification)
        info(name: "Keyboard Will beShown", with: notification)
        somethingDo(with: notification)
    }
    func keyboardDidShow(_ notification:NSNotification) {
        info(name: "Keyboard Was  Shown", with: notification)
    }
    
    //키보드가 사라질 때, 호출 되는 함수
    func keyboardWillHide(_ notification:NSNotification) {
        info(name: "Keyboard Will beHidden", with: notification)
        somethingDo(with: notification)
    }
    func keyboardDidHide(_ notification:NSNotification) {
        info(name: "Keyboard Was  Hidden", with: notification)
    }

자 이제, 키보드가 표시될 때 마다, 해당 함수들이 호출이 된다.
그럼 다음으로 넘어가자.

2. 호출된 키보드 이벤트 함수에서 키보드의 크기를 알아야, 다른 컴포넌트의 위치를 조정할 수 있다.

이벤트로 전달되는 NSNotification 클래스의 userInfo에서 해당 내용을 가져와야 알 수 있습니다.
키보드가 표시되는 Frame의 정보는 시작할 때와 표시가 다 되었을 때, 어디에 위치할지 알아낼 수 있습니다.
userInfo를 가져와서 description을 출력해 보면 아래와 같습니다.

NSConcreteNotification 0x610000242460 {name = UIKeyboardWillShowNotification; userInfo = {
    UIKeyboardAnimationCurveUserInfoKey = 7;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 258}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 796}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 538}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 667}, {375, 258}}";
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 409}, {375, 258}}";
    UIKeyboardIsLocalUserInfoKey = 1;
}}

위에서 표시되는 각 UserInfoKey에 대해서 조금 더 자세히 봅시다.
  • UIKeyboardAnimationCurveUserInfoKey : 키보드가 표시될 때 Animation Curve
  • UIKeyboardAnimationDurationUserInfoKey : 키보드 표시되는 시간
  • UIKeyboardBoundsUserInfoKey : 키보드의 Bounds로 크기를 알 수 있는 bound
  • UIKeyboardCenterBeginUserInfoKey : 키보드 표시되기 시작할 때의 중심 Point
  • UIKeyboardCenterEndUserInfoKey : 키보드 표시된 후의 중심 Point
  • UIKeyboardFrameBeginUserInfoKey : 키보드가 표시되기 시작할 때의 frame
  • UIKeyboardFrameEndUserInfoKey : 키보드가 표시된 후의 Frame
  • UIKeyboardIsLocalUserInfoKey : 지금 표시되는 키보드가 Current App에 속한 것인지 True/False로 가지고 있음. iPad의 경우 여러 App이 화면에 표시될 수 있는데, 다른 App이 표시하는 키보드인지 내가 표시한 키보드인지 구분할 수 있음. 이것이 False이면 반응하면 안됨. (iOS 9 이상에서 지원)
아래 처럼 각 호출되는 함수에서 정보를 출력해 봅니다.

SourceCode

    fileprivate func info(name str:String, with notification:NSNotification) {
        if let userInfo = notification.userInfo {
            let frameBegin = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
            let frameEnd = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
            let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber ?? NSNumber.init(value: 0)
            let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber ).doubleValue
            print("\(str) (\(Int(frameBegin.origin.x)),\(Int(frameBegin.origin.y)),\(Int(frameBegin.size.width)),\(Int(frameBegin.size.height))), (\(Int(frameEnd.origin.x)),\(Int(frameEnd.origin.y)),\(Int(frameEnd.size.width)),\(Int(frameEnd.size.height))) curve:\(curve), duration:\(duration)")
        }
    }



3. 결과로 나오는 값은 어떻게 될까요?


iPhone7
세로
Keyboard Will beShown (0,667,375,258), (0,409,375,258) curve:7, duration:0.25
Keyboard Was  Shown    (0,667,375,258), (0,409,375,258) curve:7, duration:0.25
Keyboard Will beHidden (0,409,375,258), (0,667,375,258) curve:7, duration:0.25
Keyboard Was  Hidden   (0,409,375,258), (0,667,375,258) curve:7, duration:0.25
가로
Keyboard Will beShown (0,375,667,194), (0,181,667,194) curve:7, duration:0.25
Keyboard Was  Shown    (0,375,667,194), (0,181,667,194) curve:7, duration:0.25
Keyboard Will beHidden (0,181,667,194), (0,375,667,194) curve:7, duration:0.25
Keyboard Was  Hidden   (0,181,667,194), (0,375,667,194) curve:7, duration:0.25

위 결과를 보시면, 표시되기 전에는 화면 아래 부분에 있다가 표시되면, 위로 올라오게 됩니다.
가로/세로 모드일때 따라서, 키보드의 위치와 크기가 달라집니다.

위 정보를 이용해서, UIViewController에서  ToolBar나 TextField가 키보드 아래에 있을 때, 키보드가 표시될 때 위로 이동시켜서 화면에 표시할 수 있고, 키보드가 사라질 때, 원래 위치로 이동할 수 있습니다.

댓글 5개:

  1. 작성자가 댓글을 삭제했습니다.

    답글삭제
  2. 작성자가 댓글을 삭제했습니다.

    답글삭제
  3. 안녕하세요^^
    viewWillAppear 내에
    'NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)' 코드를 입력시,

    'Value of type 'TextViewController' has no member 'keyboardWillShow'라는 해당 오류가 떠

    아래 func keyboardWillShow(_ notification:NSNotification) {
    print(notification)
    info(name: "keyboardWillShow", with: notification)
    somethingDo(with: notification)에서
    name 을 keyboardWillShow로 작성해 주었는데 오류가 계속 나는데 무슨 문제 인지 혹시 알 수 있을까요?

    답글삭제
  4. func keyboardWillShow(_ notification:NSNotification){..} 함수 앞에 @objc 를 붙여 보세요.

    @objc func keyboardWillShow(_ notification:NSNotification){..} 요렇게

    답글삭제
  5. https://github.com/davidbae/iOSCodeRepository
    를 참고해 주세요.

    답글삭제