iOS8에서 키보드 높이의 올바른 값을 얻을 수 없습니다.


83

이 코드를 사용하여 키보드의 크기를 결정했습니다.

- (void)keyboardWillChange:(NSNotification *)notification {
    NSDictionary* keyboardInfo = [notification userInfo];
    NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];

}

나는 이것을 시뮬레이터에서 실행하고있다.

문제는 iOS 8이기 때문에 키보드 제안이 올라 갔거나 아래로 밀면 다른 (올바른 것이 아님) 값을 얻습니다.

키보드 제안을 포함하여 키보드의 정확한 크기를 어떻게 얻을 수 있습니까?


keyboardFrameBeginRect로컬 좌표 로 변환하면 도움이 될 수 있습니다 .
— rmaddy

@rmaddy 정말 중요하지 않습니다. 높이 만 필요합니다.
— Eli Braginskiy 2014 년

방향에 따라 잘못 될 수 있습니다. iOS 8에서는 더 이상 문제가되지 않을 수 있지만 시도해보고 차이가 있는지 확인하십시오.
— rmaddy

@rmaddy 나는 그것을 시도하지만 슬프게도하지 않았다 도움말
— 엘리 Braginskiy을

답변:


98

사용하다

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];

좋은 대답입니다. 감사. 그 키를 사용해야한다는 것을 어떻게 알았습니까? @souvickcse
— 줄리안 오소리오에게

6
CGRect keyboardFrame = [keyboardFrameBegin CGRectValue];
— Awesomeness 2014 년

12
너무 높은, 키보드는 여전히 258이었고, 나를 위해 일을하지 않았다
— marchinram

@trycatchfinally 감사합니다
— souvickcse

1
오늘 교훈을 배웠습니다. UIKeyboardFrameEndUserInfoKey와 UIKeyboardFrameBeginUserInfoKey에는 큰 차이가 있습니다. @souvickcse 주셔서 감사합니다
— jejernig

120

iOS에 맞춤형 키보드가 도입되면서이 문제는 좀 더 복잡해졌습니다.

간단히 말해 UIKeyboardWillShowNotification 은 사용자 정의 키보드 구현에 의해 여러 번 호출 될 수 있습니다.

  1. Apple 시스템 키보드가 열려 있을 때 (세로)
    • UIKeyboardWillShowNotification은 키보드 높이 224로 전송됩니다.
  2. 때 있는 Swype 키보드 (세로) 열 :
    • UIKeyboardWillShowNotification이 키보드 높이 0으로 전송됩니다.
    • UIKeyboardWillShowNotification은 216 의 키보드 높이로 전송됩니다.
    • UIKeyboardWillShowNotification은 256 의 키보드 높이로 전송됩니다.
  3. SwiftKey 키보드 가 열릴 때 (세로) :
    • UIKeyboardWillShowNotification이 키보드 높이 0으로 전송됩니다.
    • UIKeyboardWillShowNotification은 216 의 키보드 높이로 전송됩니다.
    • UIKeyboardWillShowNotification은 키보드 높이 259로 전송됩니다.

이러한 시나리오를 하나의 코드 라인에서 적절하게 처리하려면 다음을 수행해야합니다.

UIKeyboardWillShowNotification 및 UIKeyboardWillHideNotification 알림 에 대해 관찰자를 등록합니다 .

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];    
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];

현재 키보드 높이를 추적하는 전역 변수를 만듭니다.

CGFloat _currentKeyboardHeight = 0.0f;

키보드 높이의 현재 변경에 반응하도록 keyboardWillShow 를 구현합니다 .

- (void)keyboardWillShow:(NSNotification*)notification {
   NSDictionary *info = [notification userInfo];
   CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
   CGFloat deltaHeight = kbSize.height - _currentKeyboardHeight; 
   // Write code to adjust views accordingly using deltaHeight
   _currentKeyboardHeight = kbSize.height;
}

참고 : 뷰 오프셋에 애니메이션을 적용 할 수 있습니다. 정보 사전에서 키가 값이 포함되어 UIKeyboardAnimationDurationUserInfoKey을 . 이 값은 표시되는 키보드와 동일한 속도로 변경 사항을 애니메이션하는 데 사용할 수 있습니다.

reset _currentKeyboardHeight에 keyboardWillHide 를 구현 하고 해제되는 키보드에 반응합니다.

- (void)keyboardWillHide:(NSNotification*)notification {
   NSDictionary *info = [notification userInfo];
   CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
   // Write code to adjust views accordingly using kbSize.height
   _currentKeyboardHeight = 0.0f;
}

dgangsta, 귀하의 연구는 흥미롭지 만 질문의 문제는 FrameEnd 속성 대신 FrameBegin을 얻는 것입니다. 귀하의 답변에 따르면 델타 대신 애니메이션보기 메서드에 UIViewAnimationOptionBeginFromCurrentState 플래그를 사용하는 것을 고려 했습니까?
— MikeR 2014

SwiftKey (v 1.2.3) 높이에 대해 259 대신 iOS8.1.3이 설치된 iPhone6 ​​+에서 271을 얻었습니다.
— Hemang

2
여전히 작동하는 솔루션입니까? SwiftKey를 사용할 때 259 대신 44의 높이를 얻습니다.
— KIDdAe

미친, 이것은 나를 도왔지만 이미 표시된 후 키보드 높이가 필요했기 때문에 대신 keyboardDidShow :를 관찰합니다. 이 맞춤형 키보드가 3 개의 알림을 트리거하는 반면 Apple은 하나만 트리거하는 이유는 무엇입니까? 일관성이없는 것 같습니다.
— Liron Yahdav

나처럼 가로 모드에서 iPhone에 문제가있는 경우 프레임 END 키의 출처 가 잘못 되었기 때문 입니다 (적어도 일반 iOS 10 키보드의 경우). KEYBOARD BEGIN RECT: (0.0, 375.0, 667.0, 162.0) ... KEYBOARD END RECT: (0.0, 213.0, 667.0, 162.0)
— xaphod

18

이 StackOverflow 기사를 볼 때 까지이 문제가 발생했습니다 .

UIKeyboardFrameEndUserInfoKey 변환

이 convertRect기능 을 사용하여 키보드의 크기를 사용 가능한 크기로 변환하지만 화면 방향으로 변환하는 방법을 보여줍니다 .

NSDictionary* d = [notification userInfo];
CGRect r = [d[UIKeyboardFrameEndUserInfoKey] CGRectValue];
r = [myView convertRect:r fromView:nil];

이전에, 내가 사용하는 아이 패드 앱을 가지고 UIKeyboardFrameEndUserInfoKey있지만 하지 않은 사용을 convertRect, 그리고 벌금을했다.

그러나 iOS 8에서는 더 이상 제대로 작동하지 않습니다. 갑자기 iPad에서 가로 모드로 실행되는 키보드의 높이 가 1024 픽셀 이라고보고했습니다 .

따라서 이제 iOS 8에서는이 convertRect기능 을 사용해야 합니다.


iOS8 이전 키보드 직사각형은 항상 세로 방향 화면 좌표였습니다. 가로 모드에서 높이와 너비를 수동으로 바꾸는 코드를 추가했지만 키보드 직사각형 방향이보기 방향과 일치하는 iOS 8에서 깨졌습니다. convertRect 솔루션은 iOS 7 또는 iOS 8에 대해 올바른 결과를 제공합니다.
— user1055568

7

Swift 2.0으로 작성된 dgangsta의 솔루션 과 유사합니다 .

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    guard let kbSizeValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
    guard let kbDurationNumber = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber else { return }
    animateToKeyboardHeight(kbSizeValue.CGRectValue().height, duration: kbDurationNumber.doubleValue)
}

func keyboardWillHide(notification: NSNotification) {
    guard let kbDurationNumber = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber else { return }
    animateToKeyboardHeight(0, duration: kbDurationNumber.doubleValue)
}

func animateToKeyboardHeight(kbHeight: CGFloat, duration: Double) {
    // your custom code here
}

퀵 타입과 스마일리를 표시 / 숨길 때 문제
— user3722523

이것은 소스였습니다. Swift 2.3의 사소한 차이점이지만 컴파일러의 자동 완성 제안이므로 문제가 없습니다.
— Ethan Parker

5

내가 할 extension에 대한UIViewController

extension UIViewController {
    func keyboardWillChangeFrameNotification(notification: NSNotification, scrollBottomConstant: NSLayoutConstraint) {
        let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
        let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber
        let keyboardBeginFrame = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
        let keyboardEndFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()

        let screenHeight = UIScreen.mainScreen().bounds.height
        let isBeginOrEnd = keyboardBeginFrame.origin.y == screenHeight || keyboardEndFrame.origin.y == screenHeight
        let heightOffset = keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y - (isBeginOrEnd ? bottomLayoutGuide.length : 0)

        UIView.animateWithDuration(duration.doubleValue,
            delay: 0,
            options: UIViewAnimationOptions(rawValue: UInt(curve.integerValue << 16)),
            animations: { () in
                scrollBottomConstant.constant = scrollBottomConstant.constant + heightOffset
                self.view.layoutIfNeeded()
            },
            completion: nil
        )
    }
}

다음과 같이 사용할 수 있습니다.

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChangeFrameNotification:", name: UIKeyboardWillChangeFrameNotification, object: nil)
}

...

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillChangeFrameNotification(notification: NSNotification) {
    self.keyboardWillChangeFrameNotification(notification, scrollBottomConstant: inputContainerBottom)
    // Write more to here if you want.
}

최완복 씨, 사용되는 견해는 무엇 inputContainerBottom입니까?
— Nathaniel Blumer

@Nathaniel UITextField 또는 UITextView의 bottomLayout의 하단 공간 제약. ;) 내 프로젝트에서 편집했습니다. 나는 그것을 다시 게시 할 수 있습니다
— Wanbok 최에게

4

개발자가 실제로 표시되기 전에 키보드 높이를 알아야하는 경우가있어서 인터페이스를 적절하게 사전 레이아웃 할 수 있습니다.

그렇다면 다음은 포괄적 인 사양입니다.

여기에 이미지 설명 입력

여기에는 모든 현재 버전의 iOS에서 기본적으로 켜져 있기 때문에 상단에 빠른 유형 표시 줄이 포함됩니다.

누군가 필요하다면 이것을 테스트하는 데 사용한 신속한 3 알림 설정은 다음과 같습니다.

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
}

func keyboardWillShow(notification: NSNotification) {
    guard let keyboardSize = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
    print("\(keyboardSize)")
}

1

신속한 단 하나의 문자열 :

let keyboardSize = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size

UIKeyboardFrameEndUserInfoKey항상 저장 NSValue하므로 확인할 필요가 없습니다.


0

기본 키보드와 사용자 정의 ()간에 전환 할 때 표시되는 문제를 발견했습니다.UIPickerView ) 키보드 . 사용자 지정 키보드는 기본 키보드에서 전환 한 후 162가 아닌 253 높이로 표시됩니다.

이 경우에 효과가 있었던 autocorrectionType = UITextAutocorrectionTypeNo;것은 사용자 정의 키보드로 입력 필드를 설정 하는 것입니다.

이 문제는 iOS 8에서만 발생했습니다 (시뮬레이터에서만 테스트 됨). iOS 9 (시뮬레이터 또는 기기)에서는 발생하지 않습니다.


0

한 줄이 아닌 Swift에서 ...

self.keyboardDidShowObserver = NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardDidShowNotification, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: { (notification) in
        if let userInfo = notification.userInfo, let keyboardFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
            let keyboardRect = keyboardFrameValue.CGRectValue()
            // keyboardRect.height gives the height of the keyboard
            // your additional code here...
        }
    })

0
[notificationCenter addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {

    float keyboardHeight = [[note.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;

}];
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.