Abrufen der Tastaturgröße von userInfo in Swift

81

Ich habe versucht, Code hinzuzufügen, um meine Ansicht nach oben zu verschieben, wenn die Tastatur angezeigt wird. Ich habe jedoch Probleme beim Versuch, die Objective-C-Beispiele in Swift zu übersetzen. Ich habe einige Fortschritte gemacht, aber ich stecke in einer bestimmten Zeile fest.

Dies sind die beiden Tutorials / Fragen, denen ich gefolgt bin:

So verschieben Sie den Inhalt von UIViewController nach oben, wenn die Tastatur mithilfe von Swift angezeigt wird: http://www.ioscreator.com/tutorials/move-view-when-keyboard-appears

Hier ist der Code, den ich derzeit habe:

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) {
    //
}

Im Moment erhalte ich einen Fehler in dieser Zeile:

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

Wenn mir jemand mitteilen könnte, wie diese Codezeile aussehen soll, sollte ich es schaffen, den Rest selbst herauszufinden.

user3746428
quelle

Antworten:

185

Es gibt einige Probleme in Ihrer Leitung:

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
  • notification.userInfoGibt ein optionales Wörterbuch zurück [NSObject : AnyObject]?, sodass es vor dem Zugriff auf seine Werte entpackt werden muss.
  • Das Objective-C NSDictionaryist einem nativen Swift-Wörterbuch zugeordnet, daher müssen Sie die Indexsyntax ( dict[key]) des Wörterbuchs verwenden, um auf die Werte zuzugreifen.
  • Der Wert muss umgewandelt werden, NSValuedamit Sie ihn aufrufen CGRectValuekönnen.

All dies kann mit einer Kombination aus optionaler Zuordnung, optionaler Verkettung und optionalen Abgüssen erreicht werden:

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
}

Oder in einem Schritt:

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

Update für 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
}

Oder in einem Schritt:

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

Update für Swift 5 (Xcode 11.6):

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

Ich empfehle die Verwendung keyboardFrameEndUserInfoKeyanstelle von, keyboardFrameBeginUserInfoKeyda die Tastatur die anfängliche Renderhöhe nach der ersten Anzeige auf älteren iOS-Geräten ändert.

Martin R.
quelle
@ MartinR Es tut mir leid, dass ich in den falschen Beitrag kommentiert habe :) Entschuldigung
Lamour
Hallo, ich versuche, die Tastaturgröße mit Benachrichtigungen zu ermitteln, aber ich kann sie nicht zum Laufen bringen. Ich füge den Beobachter in viewDidload hinzu (auch viewWillAppear ausprobiert). NSNotificationCenter.defaultCenter (). AddObserver (self, Selektor: "keyboardWillShow:", Name: UIKeyboardWillShowNotification, Objekt: nil) Die Methode wird jedoch nicht aufgerufen. Ich habe es auf einem realen Gerät und dem Simulator versucht. Irgendein Rat? Vielen Dank.
TheMouse
Es gibt cgRectValue in "one step" Antwort, sollte aber CGRectValue
Vladimirs Matusevics
@krotov Der erste Teil der Antwort bezieht sich auf Swift 2, der zweite Teil auf Swift 3. Diese Eigenschaft wurde zwischen diesen Releases umbenannt.
Martin R
1
Ich denke, es ist besser, UIKeyboardFrameEndUserInfoKey anstelle von UIKeyboardFrameBeginUserInfoKey für den Fall zu verwenden, wenn sich der Tastaturrahmen ändert (prädiktiv aktiviert oder auf Emoji-Tastatur für iOS 9 oder höher
umgeschaltet
18

Für noch weniger Code sollten Sie sich DIESES ansehen

Es war sehr hilfreich für mich. Sie müssen nur die Ansichtsbeschränkung in den Ansichtscontroller aufnehmen und die beiden von Ihnen hinzugefügten Beobachter verwenden. Verwenden Sie dann einfach die folgenden Methoden (hier wird eine Tabellenansicht verschoben)

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()
                })
            }
        }
    }

und

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() })
  }
} }
Nikolaus
quelle
1
Ich bekam diese Antwort erst, als ich sie woanders sah, wo mir klar wurde, dass tableViewBottomConstraint ein Ausgang zum Xib ist. Dann wurde klar, dass dies die perfekte Antwort ist! (Wenn Sie Auto-Layout verwenden)
Joris van Liempd iDeveloper
@JorisvanLiempd Ja, ich verwende das automatische Layout. Gut, dass es dir geholfen hat.
Nicholas
Es scheint, dass die Animation ohne den Animationsblock kostenlos ist. was in dieser Antwort sowieso nicht der Tastaturkurve und -dauer folgt.
AmitP
11

Wenn Sie ein Storyboard verwenden, anstatt die Ansicht selbst zu bearbeiten, können Sie das automatische Layout nutzen.

(Dies ist eine bereinigte Version von Nicholas 'Antwort)

Richten Sie ein Benachrichtigungscenter ein, um Sie über das Erscheinen und Verschwinden der Tastatur zu informieren:

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)

}

Und stellen Sie sicher, dass Sie die Beobachter entfernen, wenn Sie sie nicht mehr benötigen:

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)
}

Legen Sie im Storyboard die unterste Einschränkung fest. Erstellen Sie einen Ausgang für diese Einschränkung:

Geben Sie hier die Bildbeschreibung ein

und legen Sie die Konstanteneigenschaft der Einschränkung fest, wenn die Tastatur angezeigt oder ausgeblendet wird:

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()
}

Immer wenn die Tastatur erscheint oder verschwindet, kümmert sich das automatische Layout um alles.

DudeOnRock
quelle
4

Swift 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
    }

Swift 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
}
Barlow Tucker
quelle
Danke, es hilft mir sehr!
Javimuu
3

Dies hat mir geholfen: 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()
Paul
quelle
1

Sie können diese eine Zeile für Ihre Zeile verwenden

var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size
Avinash
quelle
3
Es ist nicht sicher, das Auspacken des Tastaturrahmens aus diesem Wörterbuch zu erzwingen. Konnte nicht da sein.
Adama
1

Swift 3: UPDATE

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)
}
Kevin Sabbe
quelle
1

Swift - Tastaturhöhe Von keyboardWillShowNotification

Sie können eine Einschränkung oder einen anderen Wert auf die Größe der Tastatur vergrößern oder verkleinern, indem Sie Daten von der Tastatur verwenden. Benachrichtigungen werden angezeigt / ausgeblendet.

Mit einer Layoutbeschränkung

Dieser minimale Code registriert die Benachrichtigung, dass die Tastatur eine Einschränkung basierend auf ihrer Größe anzeigt und aktualisiert.

@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
    }
}

Mit einer ScrollView

Auf die gleiche Weise wird der Inhalt einer Bildlaufansicht basierend auf der Tastaturgröße aktualisiert.

@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
  }
}
Zeitschmied
quelle
1

Einzelheiten

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

Lösung

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)
    }
}

Verwendung

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") }
}

Vollständige Probe

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") }
}

Ergebnis

Geben Sie hier die Bildbeschreibung ein

Log

Geben Sie hier die Bildbeschreibung ein

Wassili Bodnarchuk
quelle
0

Swift 3.0

Hier ist ein Beispiel für das Abrufen der Tastaturgröße und das Animieren einer Ansicht nach oben. In meinem Fall verschiebe ich eine UIView mit meinen UITextFields nach oben, wenn ein Benutzer mit der Eingabe beginnt, damit er ein Formular ausfüllen und trotzdem die Schaltfläche zum Senden unten sehen kann.

Ich habe der unteren Platzbeschränkung der Ansicht, die ich animieren wollte, einen Ausgang hinzugefügt und den Namen myViewsBottomSpaceConstraint:

@IBOutlet weak var myViewsBottomSpaceConstraint: NSLayoutConstraint!

Ich habe dann meiner schnellen Klasse den folgenden Code hinzugefügt:

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()
}
mobilecat
quelle
0

Für Xamarin können Sie c # 6 verwenden

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;
   }
marcel
quelle
0

In Swift 4.2 können Sie UIResponder.keyboardFrameEndUserInfoKey verwenden

guard let userInfo = notification.userInfo , let keyboardFrame:CGRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect  else { return  }```
Aybek Can Kaya
quelle