레이블이 Keyboard인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Keyboard인 게시물을 표시합니다. 모든 게시물 표시

2017/05/01

iOS & Swift: Keyboard로 사용자 입력할 때, ToolBar 위로 이동하기

이전 글인 Keyboard 이벤트를 이용해서, ToolBar를 이동하는 예제를 만들어 봅니다.

ViewController에서, 하단에 Toolbar가 있고, 사용자가 입력을 할 때, View를 위로 이동시켜서, 입력하는 내용이 화면에 표시되도록 하면, 어떤 내용을 입력하는지 알기 쉬운 UI가 됩니다.

ToolBar만 위로 이동해도 되지만, AutoLayout의 내용들을 다 무시하게 되므로, 전체 View를 Keyboard표시되는 것 만큼 위로 이동하게 만들어 봅니다.



 Keyboard 이벤트 설명 블로그에서 이벤트 등록과 이벤트 발생 때, 실행되는 함수를 등록하는 방법을 이미 설명했습니다.
이제 표시될 때, ToolBar를 위로 올려주고, 입력이 끝나면 밑으로 내려줘야 합니다. 그리고, 입력 중에 화면이 회전되면, 적당하게 ToolBar의 위치를 옮겨줘야 합니다.
위로 얼마나 올려야 되는지는

키보드 표시될 때와, 사라질 때 함수 호출하기.

    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.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    func keyboardWillShow(_ notification:NSNotification) {
        //키보드가 표시 될때, ToolBar의 위치를 올려준다.
        moveToolbarUp(with: notification)
    }
    func keyboardWillHide(_ notification:NSNotification) {
        //키보드가 사라질 때, ToolBar의 위치를 아래로 내려준다.
        moveToolbarDown(with: notification)
    }

Toolbar를 위로 올려주고, 아래로 내려주는 함수
    fileprivate func moveToolbarUp(with notification:NSNotification) {
        self.moveToolBar(isUp: true, with: notification)
    }
    fileprivate func moveToolbarDown(with notification:NSNotification) {
        self.moveToolBar(isUp: false, with: notification)
    }
    fileprivate func moveToolBar(isUp up:Bool, with notification:NSNotification) {
        if let userInfo = notification.userInfo {
            //let beginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
            let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
            let animationOptions = UIViewAnimationOptions(rawValue: (userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).uintValue)
            
            let frame = self.toolbar.frame
            let rect:CGRect = CGRect(x: frame.origin.x,
                                     y: frame.origin.y + endFrame.size.height * (up ? -1 : 1),
                                     width: frame.size.width,
                                     height: frame.size.height)
            UIView.animate(withDuration: duration,
                           delay: 0.0,
                           options: animationOptions,
                           animations: { () -> Void in
                            self.toolbar.frame = rect
            }, completion: nil)
            
        }else{
            //UserInfo가 없을 경우..
        }
    } 

ToolBar가 올라가 있는 상태에서 화면을 옆으로 돌리면, 툴바의 위치가 이상하게 되어 버리는 예외를 처리하기 위해서, 화면이 회전할 때, 키보드를 사라지게 해줍니다. 더 좋은 방법이 있겠지만, 이정도로 마무리..

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        //화면이 옆으로 돌아갈 때, 호출되는 이벤트로, 이벤트 발생 시, 키보드를 아래로 내려주면 이동 후에 다시 선택하면 되도록 한다
        self.inputTextField.resignFirstResponder();
    }


2017/03/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가 키보드 아래에 있을 때, 키보드가 표시될 때 위로 이동시켜서 화면에 표시할 수 있고, 키보드가 사라질 때, 원래 위치로 이동할 수 있습니다.

2014/01/17

[iOS] Keyboard가 표시될 때, Toolbar의 위치 이동하기.

 키보드가 표시될 때, 발생하는 이벤트를 받아오는 방법은 블로그 ([iOS] Keyboard가 표시될 때, 사라질 때 이벤트와 그 키보드의 위치는?)를 참고하시면 됩니다.
 이번에는 아래에 표시되는 toolbar를 키보드가 표시되는 Animation에 맞춰서 위로 이동하고, 아래로 이동하도록 정리합니다.

1. 관련한 정보는 어디에서 가져오나요?

keyboard가 표시될 경우, NSNotification 객체에 정보를 담아서 전달이 됩니다. 이 notification에서 해당 정보를 찾아서 가져오면 됩니다.

2. 어떤 정보가 필요할 까요?

Toolbar에 위치를 이동시키는데, 이동 시간과, 애니메이션 방법, 위치가 필요합니다.
키보드가 나타나는 시간동안 어떤 형태로 애니메이션으로 어디에 표시되는지를 알면, 그와 같은 방식으로 이동하면 같이 붙어서 이동하는 것처럼 표시가 됩니다.
source code
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrame;
    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrame];

키보드가 표시될 때, 사라질 때, Toolbar에 대한 Animation을 아래 소스와 같이 설정해 두면 됩니다.

3. 소스

source code
#pragma mark - Toolbar animation helpers

// Helper method for moving the toolbar frame based on user action
- (void)moveToolBarUp:(BOOL)up 
forKeyboardNotification:(NSNotification *)notification
{
    NSDictionary *userInfo = [notification userInfo];
    
    // Get animation info from userInfo
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrame;
    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] 
                                      getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] 
                                      getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] 
                                      getValue:&keyboardFrame];
    
    // Animate up or down
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];
    [UIView setAnimationCurve:animationCurve];
    
    UIToolbar *toolbar = self.navigationController.toolbar;
    [toolbar setFrame:CGRectMake(toolbar.frame.origin.x,
                                 toolbar.frame.origin.y + 
        (keyboardFrame.size.height * (up ? -1 : 1)), toolbar.frame.size.width, toolbar.frame.size.height)];
    [UIView commitAnimations];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    // move the toolbar frame up as keyboard animates into view
    [self moveToolBarUp:YES 
forKeyboardNotification:notification];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    // move the toolbar frame down as keyboard animates into view
    [self moveToolBarUp:NO 
forKeyboardNotification:notification];
}


4. 결과 화면,

 


2013/12/29

[iOS] Keyboard가 표시될 때, 사라질 때 이벤트와 그 키보드의 위치는?

 iOS에서 키보드가 표시될 때, 입력부분이 아래에 있다면, 화면이 위로 밀려 올라가야 합니다.이 때, 키보드의 크기를 알아야, 현재 화면을 위로 밀어 올릴 수 있습니다.

 UITableViewController는 자동으로 내부적으로 크기를 줄이고, 입력하는 부분을 위로 올려주게 되어 있습니다.

만약 일반적인 ViewController를 사용해서 화면을 구성한 경우에는 위치를 변경해 주어야 합니다.

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

키보드가 표시될 때, 전달되는 이벤트는.. 
  • UIKeyboardWillShowNotification : 키보드 표시되기 전, 전달되는 이벤트
  • UIKeyboardDidShowNotification : 키보드 표시되고 난 후, 전달되는 이벤트
  • UIKeyboardWillHideNotification : 키보드 사라지기 전,
  • UIKeyboardDidHideNotification : 키보드 사라진 후, 이벤트
  • UIKeyboardWillChangeFrameNotification : 키보드 모양이 바뀌기 전 (iOS5 이상)
  • UIKeyboardDidChangeFrameNotification : 키보드 모양이 바뀐 후 (iOS5 이상)

필요한 이벤트를 알림센터에 등록해서, 각 이벤트에 해당하는 메시지 함수를 호출 할 수 있습니다.
source code

#pragma mark - Keyboard detect function
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
    [defaultCenter addObserver:self
                      selector:@selector(keyboardWillbeShown:) //표시되기 전
                          name:UIKeyboardWillShowNotification object:nil];
    [defaultCenter addObserver:self
                      selector:@selector(keyboardWasShown:)    //표시된 후
                          name:UIKeyboardDidShowNotification object:nil];
    [defaultCenter addObserver:self
                      selector:@selector(keyboardWillBeHidden:) //사라지기 전
                          name:UIKeyboardWillHideNotification object:nil];
    [defaultCenter addObserver:self
                      selector:@selector(keyboardWasHidden:)    //사라진 후
                          name:UIKeyboardDidHideNotification object:nil];
    
}

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

 이벤트로 전달되는 NSNotification클래스의 userInfo에 해당 내용이 추가되어 있습니다.
키보드의 크기는 UIKeyboardFrameBeginUserInfoKey를 통해서 읽어 올 수 있는데, 다른 값들은 차이를 알수가 없었습니다.
  • UIKeyboardFrameBeginUserInfoKey : 키보드가 표시되기 시작할 때의 크기를 가지고 있습니다. NSValue형태로 CGRect 값을 가지고 있습니다.
  • UIKeyboardFrameEndUserInfoKey
  • UIKeyboardAnimationCurveUserInfoKey:
  • UIKeyboardCenterBeginUserInfoKey : CGPoint로 키보드 중심 위치?
  • UIKeyboardCenterEndUserInfoKey :   
  • UIKeyboardBoundsUserInfoKey
아래의 소스코드처럼, Begin과 End이 값을 각 이벤트에 따라서 읽어 봤지만 차이가 없네요.
source code
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWillBeShown: (NSNotification *) aNotification
{
    // Get Keyboard Size
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize kbSize2 = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    double anmationDuration = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] doubleValue];
    NSLog(@"keyboard Will beShown: %@, %@, duration:%lf", NSStringFromCGSize(kbSize), NSStringFromCGSize(kbSize2), anmationDuration);
}

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

iPhone 3.5-inch와 4.0-inch의 height의 길이 차이가 나지만, iPad는 Scale이 같으므로 동일한 결과가 나왔습니다.
iPhone Retina 3.5-inch
세로 
 keyboard Will beShown:   {320, 216}, {320, 216}, duration:7.
 keyboard WasShown:       {320, 216}, {320, 216}
 keyboard Will beHidden:  {320, 216}, {320, 216}
 keyboard WasHidden:      {320, 216}, {320, 216} 

가로
 keyboard Will beShown:   {162, 480}, {162, 480}, duration:7.
 keyboard WasShown:       {162, 480}, {162, 480}
 keyboard Will beHidden:  {162, 480}, {162, 480}
 keyboard WasHidden:      {162, 480}, {162, 480}

iPhone Retina 4.0-inch
세로
 keyboard Will beShown:   {320, 216}, {320, 216}, duration:7.000000
 keyboard WasShown:       {320, 216}, {320, 216}
 keyboard Will beHidden:  {320, 216}, {320, 216}
 keyboard WasHidden:      {320, 216}, {320, 216}
가로
 keyboard Will beShown:   {162, 568}, {162, 568}, duration:7.000000
 keyboard WasShown:       {162, 568}, {162, 568} //너비의 차이..
 keyboard Will beHidden:  {162, 568}, {162, 568}
 keyboard WasHidden:      {162, 568}, {162, 568}

iPad
세로
 keyboard Will beShown:   {768, 264},  {768, 264}, duration:7.000000
 keyboard WasShown:       {768, 264},  {768, 264}
 keyboard Will beHidden:  {768, 264},  {768, 264}
 keyboard WasHidden:      {768, 264},  {768, 264}
가로
 keyboard Will beShown:   {352, 1024}, {352, 1024}, duration:7.000000
 keyboard WasShown:       {352, 1024}, {352, 1024}
 keyboard Will beHidden:  {352, 1024}, {352, 1024}
 keyboard WasHidden:      {352, 1024}, {352, 1024}

iPad Retina
세로
 keyboard Will beShown:   {768, 264},  {768, 264}, duration:7.000000
 keyboard WasShown:       {768, 264},  {768, 264} //iPad와 동일.
 keyboard Will beHidden:  {768, 264},  {768, 264}
 keyboard WasHidden:      {768, 264},  {768, 264}
가로
 keyboard Will beShown:   {352, 1024}, {352, 1024}, duration:7.000000
 keyboard WasShown:       {352, 1024}, {352, 1024}
 keyboard Will beHidden:  {352, 1024}, {352, 1024}
 keyboard WasHidden:      {352, 1024}, {352, 1024}