Swift의 userInfo에서 키보드 크기 가져 오기


82

키보드가 나타날 때 뷰를 위로 이동하는 코드를 추가하려고 시도했지만 Objective-C 예제를 Swift로 변환하는 데 문제가 있습니다. 나는 약간의 진전을 이루었지만 특정 라인에 갇혀 있습니다.

다음은 내가 따라온 두 가지 자습서 / 질문입니다.

Swift http://www.ioscreator.com/tutorials/move-view-when-keyboard-appears를 사용하여 키패드가 나타날 때 UIViewController의 콘텐츠를 위로 이동하는 방법

현재 가지고있는 코드는 다음과 같습니다.

override func viewWillAppear(animated: Bool) {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
    UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    let frame = self.budgetEntryView.frame
    frame.origin.y = frame.origin.y - keyboardSize
    self.budgetEntryView.frame = frame
}

func keyboardWillHide(notification: NSNotification) {
    //
}

현재이 줄에 오류가 발생합니다.

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))

누군가가이 코드 줄이 무엇인지 알려줄 수 있다면 나머지는 직접 알아 내야합니다.

답변:


186

라인에 몇 가지 문제가 있습니다.

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
  • notification.userInfo선택적 사전을 반환 [NSObject : AnyObject]?하므로 값에 액세스하기 전에 래핑을 해제해야합니다.
  • Objective-C NSDictionary는 Swift 네이티브 사전에 매핑되므로 dict[key]값에 액세스하려면 사전 아래 첨자 구문 ( )을 사용해야합니다.
  • NSValue호출 할 수 있도록 값을 캐스트해야 CGRectValue합니다.

이 모든 것은 선택적 할당, 선택적 체인 및 선택적 캐스트의 조합으로 달성 할 수 있습니다.

if let userInfo = notification.userInfo {
   if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
       // ...
   } else {
       // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
   }
} else {
   // no userInfo dictionary in notification
}

또는 한 단계로 :

if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    // ...
}

Swift 3.0.1 (Xcode 8.1) 업데이트 :

if let userInfo = notification.userInfo {
    if let keyboardSize = userInfo[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
        // ...
    } else {
        // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
    }
} else {
    // no userInfo dictionary in notification
}

또는 한 단계로 :

if let keyboardSize = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    // ...
}

Swift 5 (Xcode 11.6) 업데이트 :

 guard let userInfo = notification.userInfo,
              let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }

이전 iOS 장치에서 처음 표시 한 후 키보드가 초기 렌더링 높이를 변경하므로 keyboardFrameEndUserInfoKey대신 사용 하는 것이 좋습니다 keyboardFrameBeginUserInfoKey.


미안 내가 잘못 포스트에 댓글을 달았하고 @MartinR : 죄송합니다
라 무르

안녕하세요, 알림으로 키보드 크기를 가져 오려고하는데 작동하지 않습니다. viewDidload에 관찰자를 추가합니다 (viewWillAppear도 시도했습니다). NSNotificationCenter.defaultCenter (). addObserver (self, selector : "keyboardWillShow :", name : UIKeyboardWillShowNotification, object : nil)하지만 메서드가 호출되지 않습니다. 실제 장치와 시뮬레이터에서 시도했습니다. 어떤 충고? 대단히 감사합니다.
theMouse

이 cgRectValue는 "한 단계"대답이지만, CGRectValue해야한다
Vladimirs Matusevics

@krotov 대답의 첫 번째 부분은 Swift 2에 대한 것이고 두 번째 부분은 Swift 3에 대한 것입니다.이 속성은이 릴리스 사이에 이름이 변경되었습니다.
Martin R

1
나는 키보드 프레임 변경 (예측이 가능 이상 아이폰 OS 9에 대한 이모티콘 키보드로 전환) 때 경우 대신 UIKeyboardFrameBeginUserInfoKey의 UIKeyboardFrameEndUserInfoKey를 사용하는 것이 더 생각
crcalin

18

더 적은 코드의 경우 THIS를 살펴보십시오.

정말 도움이되었습니다. 뷰 컨트롤러에 뷰 제약을 포함하고 추가 한 두 옵저버를 사용하기 만하면됩니다. 그런 다음 다음 방법을 사용하십시오 (여기서는 tableView를 이동한다고 가정합니다)

func keyboardWillShow(sender: NSNotification) {
        if let userInfo = sender.userInfo {
            if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().size.height {
                tableViewBottomConstraint.constant = keyboardHeight
                UIView.animateWithDuration(0.25, animations: { () -> Void in
                    self.view.layoutIfNeeded()
                })
            }
        }
    }

func keyboardWillHide(sender: NSNotification) {
if let userInfo = sender.userInfo {
  if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().size.height {
    tableViewBottomConstraint.constant = 0.0
    UIView.animateWithDuration(0.25, animations: { () -> Void in self.view.layoutIfNeeded() })
  }
} }

1
나는 다른 곳에서 그것을 볼 때 까지이 대답을 얻지 못했습니다. tableViewBottomConstraint가 Xib의 출구라는 것이 분명해졌습니다. 그러면 이것이 완벽한 답이라는 것이 분명해졌습니다! (당신은 자동 레이아웃을 사용하는 경우)
요리스 반 Liempd iDeveloper

@JorisvanLiempd 예, 자동 레이아웃을 사용하고 있습니다. 도움이되었습니다.
Nicholas

애니메이션 블록없이 애니메이션이 무료로 제공되는 것 같습니다. 이 답변에서 어쨌든 키보드 곡선과 지속 시간을 따르지 않습니다.
AmitP 2016

11

뷰 자체를 조작하는 대신 스토리 보드를 사용하는 경우 자동 레이아웃을 활용할 수 있습니다.

(이것은 Nicholas 's Answer의 정리 된 버전입니다)

키보드의 모양과 사라짐을 알리도록 알림 센터를 설정하십시오.

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

}

관찰자가 더 이상 필요하지 않으면 제거해야합니다.

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}

스토리 보드 내에서 하단 제약을 설정합니다. 해당 제약의 출구를 만듭니다.

여기에 이미지 설명 입력

키보드가 표시되거나 숨겨 질 때 제약 조건의 상수 속성을 설정합니다.

func keyboardWillShow(notification: NSNotification) {
    guard let keyboardHeight = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue.size.height else {
        return
    }
    nameOfOutlet.constant = keyboardHeight
    view.layoutIfNeeded()
}

func keyboardWillHide(notification: NSNotification) {
    nameOfOutlet.constant = 0.0
    view.layoutIfNeeded()
}

이제 키보드가 나타나거나 사라질 때마다 자동 레이아웃이 모든 것을 처리합니다.


4

스위프트 2

func keyboardWasShown(notification:NSNotification) {
        guard let info:[NSObject:AnyObject] = notification.userInfo,
            let keyboardSize:CGSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size else { return }

        let insets:UIEdgeInsets = UIEdgeInsetsMake(self.scrollView.contentInset.top, 0.0, keyboardSize.height, 0.0)

        self.scrollView.contentInset = insets
        self.scrollView.scrollIndicatorInsets = insets
    }

스위프트 3

func keyboardWasShown(notification:NSNotification) {
    guard let info:[AnyHashable:Any] = notification.userInfo,
        let keyboardSize:CGSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size else { return }

    let insets:UIEdgeInsets = UIEdgeInsets(top: self.scrollView.contentInset.top, left: 0.0, bottom: keyboardSize.height, right: 0.0)

    self.scrollView.contentInset = insets
    self.scrollView.scrollIndicatorInsets = insets
}

감사합니다. 정말 도움이됩니다!
javimuu

3

이것은 나를 도왔습니다 : https://developer.apple.com/library/ios/samplecode/UICatalog/Listings/Swift_UICatalog_TextViewController_swift.html

let userInfo = notification.userInfo!

let animationDuration: NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as NSNumber).doubleValue
let keyboardScreenBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()

1

이 한 줄을 줄에 사용할 수 있습니다.

var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size

3
해당 사전에서 키보드 프레임을 강제로 풀어주는 것은 안전하지 않습니다. 거기있을 수 없습니다.
Adama 2015

1

Swift 3 : 업데이트

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
}

1

Swift-keyboardWillShowNotification의 키보드 높이

키보드 Will / did Show / hide Notifications의 데이터를 사용하여 제약 조건 또는 기타 값을 키보드 크기로 늘리거나 줄일 수 있습니다.

레이아웃 제약

이 최소 코드는 키보드가 크기에 따라 제약 조건을 표시하고 업데이트한다는 알림을 등록합니다.

@IBOutlet weak var keyboardConstraint: NSLayoutConstraint!
let keyboardConstraintMargin:CGFloat = 20

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { (notification) in
        if let keyboardSize = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect {
            self.keyboardConstraint.constant = keyboardSize.height + self.keyboardConstraintMargin
        }
    }
    NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidHideNotification, object: nil, queue: nil) { (notification) in
        self.keyboardConstraint.constant = self.keyboardConstraintMargin
    }
}

ScrollView 사용

같은 방식으로 키보드 크기에 따라 스크롤 뷰의 내용 삽입을 업데이트합니다.

@IBOutlet weak var scrollView: UIScrollView!

override func viewDidLoad() {
  super.viewDidLoad()
  NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { (notification) in
    if let keyboardSize = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect {
      let insets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
      self.scrollView.contentInset = insets
      self.scrollView.scrollIndicatorInsets = insets
    }
  }
  NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidHideNotification, object: nil, queue: nil) { (notification) in
    let insets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    self.scrollView.contentInset = insets
    self.scrollView.scrollIndicatorInsets = insets
  }
}

1

세부

  • Xcode 버전 11.1 (11A1027), iOS 13, Swift 5

해결책

import UIKit

protocol KeyboardNotificationsDelegate: class {
    func keyboardWillShow(notification: NSNotification)
    func keyboardWillHide(notification: NSNotification)
    func keyboardDidShow(notification: NSNotification)
    func keyboardDidHide(notification: NSNotification)
}

extension KeyboardNotificationsDelegate {
    func keyboardWillShow(notification: NSNotification) {}
    func keyboardWillHide(notification: NSNotification) {}
    func keyboardDidShow(notification: NSNotification) {}
    func keyboardDidHide(notification: NSNotification) {}
}

class KeyboardNotifications {

    fileprivate var _isEnabled: Bool
    fileprivate var notifications: [KeyboardNotificationsType]
    fileprivate weak var delegate: KeyboardNotificationsDelegate?

    init(notifications: [KeyboardNotificationsType], delegate: KeyboardNotificationsDelegate) {
        _isEnabled = false
        self.notifications = notifications
        self.delegate = delegate
    }

    deinit { if isEnabled { isEnabled = false } }
}

// MARK: - enums

extension KeyboardNotifications {

    enum KeyboardNotificationsType {
        case willShow, willHide, didShow, didHide

        var selector: Selector {
            switch self {
                case .willShow: return #selector(keyboardWillShow(notification:))
                case .willHide: return #selector(keyboardWillHide(notification:))
                case .didShow: return #selector(keyboardDidShow(notification:))
                case .didHide: return #selector(keyboardDidHide(notification:))
            }
        }

        var notificationName: NSNotification.Name {
            switch self {
                case .willShow: return UIResponder.keyboardWillShowNotification
                case .willHide: return UIResponder.keyboardWillHideNotification
                case .didShow: return UIResponder.keyboardDidShowNotification
                case .didHide: return UIResponder.keyboardDidHideNotification
            }
        }
    }
}

// MARK: - isEnabled

extension KeyboardNotifications {

    private func addObserver(type: KeyboardNotificationsType) {
        NotificationCenter.default.addObserver(self, selector: type.selector, name: type.notificationName, object: nil)
    }

    var isEnabled: Bool {
        set {
            if newValue {
                for notificaton in notifications { addObserver(type: notificaton) }
            } else {
                NotificationCenter.default.removeObserver(self)
            }
            _isEnabled = newValue
        }

        get { return _isEnabled }
    }

}

// MARK: - Notification functions

extension KeyboardNotifications {

    @objc func keyboardWillShow(notification: NSNotification) {
        delegate?.keyboardWillShow(notification: notification)
    }

    @objc func keyboardWillHide(notification: NSNotification) {
        delegate?.keyboardWillHide(notification: notification)
    }

    @objc func keyboardDidShow(notification: NSNotification) {
        delegate?.keyboardDidShow(notification: notification)
    }

    @objc func keyboardDidHide(notification: NSNotification) {
        delegate?.keyboardDidHide(notification: notification)
    }
}

용법

class ViewController: UIViewController {

    private lazy var keyboardNotifications: KeyboardNotifications! = {
        return KeyboardNotifications(notifications: [.willShow, .willHide, .didShow, .didHide], delegate: self)
    }()

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        keyboardNotifications.isEnabled = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        keyboardNotifications.isEnabled = false
    }
}

extension ViewController: KeyboardNotificationsDelegate {

    // If you don't need this func you can remove it
    func keyboardWillShow(notification: NSNotification) {
        print("keyboardWillShow")
        guard   let userInfo = notification.userInfo as? [String: NSObject],
                let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
        print("keyboardFrame: \(keyboardFrame)")
    }

    // If you don't need this func you can remove it
    func keyboardWillHide(notification: NSNotification) { print("keyboardWillHide") }

    // If you don't need this func you can remove it
    func keyboardDidShow(notification: NSNotification) { print("keyboardDidShow") }

    // If you don't need this func you can remove it
    func keyboardDidHide(notification: NSNotification) { print("keyboardDidHide") }
}

전체 샘플

import UIKit

class ViewController: UIViewController {

    private lazy var keyboardNotifications: KeyboardNotifications! = {
        return KeyboardNotifications(notifications: [.willShow, .willHide, .didShow, .didHide], delegate: self)
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        let textField = UITextField(frame: CGRect(x: 40, y: 40, width: 200, height: 30))
        textField.borderStyle = .roundedRect
        view.addSubview(textField)

        let gesture = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:)))
        view.addGestureRecognizer(gesture)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        keyboardNotifications.isEnabled = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        keyboardNotifications.isEnabled = false
    }
}

 extension ViewController: KeyboardNotificationsDelegate {

    // If you don't need this func you can remove it
    func keyboardWillShow(notification: NSNotification) {
        print("keyboardWillShow")
        guard   let userInfo = notification.userInfo as? [String: NSObject],
                let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
        print("keyboardFrame: \(keyboardFrame)")
    }

    // If you don't need this func you can remove it
    func keyboardWillHide(notification: NSNotification) { print("keyboardWillHide") }

    // If you don't need this func you can remove it
    func keyboardDidShow(notification: NSNotification) { print("keyboardDidShow") }

    // If you don't need this func you can remove it
    func keyboardDidHide(notification: NSNotification) { print("keyboardDidHide") }
}

결과

여기에 이미지 설명 입력

로그

여기에 이미지 설명 입력


0

스위프트 3.0

다음은 키보드 크기를 검색하고이를 사용하여 뷰를 위쪽으로 애니메이션하는 예입니다. 제 경우에는 사용자가 입력을 시작할 때 UITextFields가 포함 된 UIView를 위로 이동하여 양식을 완성하고 하단에 제출 버튼을 계속 볼 수 있습니다.

애니메이션을 적용하려는 뷰 의 하단 공간 제약 조건 에 콘센트를 추가하고 이름을 myViewsBottomSpaceConstraint다음 과 같이 지정했습니다 .

@IBOutlet weak var myViewsBottomSpaceConstraint: NSLayoutConstraint!

그런 다음 신속한 클래스에 다음 코드를 추가했습니다.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
}

func keyboardWillShow(notification: NSNotification) {

    let userInfo = notification.userInfo as! [String: NSObject] as NSDictionary
    let keyboardFrame = userInfo.value(forKey: UIKeyboardFrameEndUserInfoKey) as! CGRect
    let keyboardHeight = keyboardFrame.height
    myViewsBottomSpaceConstraint.constant = keyboardHeight
    view.layoutIfNeeded()
}

func keyboardWillHide(notification: NSNotification) {
    myViewsBottomSpaceConstraint.constant = 0.0
    view.layoutIfNeeded()
}

0

xamarin의 경우 c # 6을 사용할 수 있습니다.

private void KeyboardWillChangeFrame(NSNotification notification)
{
        var keyboardSize = notification.UserInfo.ValueForKey(UIKeyboard.FrameEndUserInfoKey) as NSValue;
        if (keyboardSize != null)
        {
            var rect= keyboardSize.CGRectValue;
            //do your stuff here
        }
}

C # 7

  private void KeyboardWillChangeFrame(NSNotification notification)
   {
       if (!(notification.UserInfo.ValueForKey(UIKeyboard.FrameEndUserInfoKey) is NSValue keyboardSize)) return;
       var rect= keyboardSize.CGRectValue;
   }

0

스위프트 4.2 당신은 UIResponder.keyboardFrameEndUserInfoKey을 사용할 수 있습니다

guard let userInfo = notification.userInfo , let keyboardFrame:CGRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect  else { return  }```
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.