Pobieranie rozmiaru klawiatury z userInfo w Swift

Próbowałem dodać trochę kodu, aby przenieść mój widok w górę, gdy pojawi się klawiatura, jednak mam problemy z tłumaczeniem przykładów Objective-C na Swift. Poczyniłem pewne postępy, ale utknąłem na jednej konkretnej linii.

Oto dwa tutoriale/pytania, które śledziłem:

Jak przenieść zawartość UIViewController w górę, gdy pojawi się Klawiatura za pomocą Swift http://www.ioscreator.com/tutorials/move-view-when-keyboard-appears

Oto kod, który aktualnie posiadam:

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

W tej chwili dostaję błąd w tej linii:

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
Jeśli ktoś mógłby mi powiedzieć, jaka powinna być ta linijka kodu, resztę sam bym wymyślił.
Author: Community, 2014-08-22

10 answers

Są pewne problemy w linii

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
  • notification.userInfo zwraca opcjonalny słownik [NSObject : AnyObject]?, musi więc zostać rozpakowany przed uzyskaniem dostępu do jego wartości.
  • Objective-C NSDictionary jest mapowany do słownika Swift native, więc musisz użyj składni indeksu słownikowego (dict[key]), aby uzyskać dostęp do wartości.
  • wartość musi być oddana do NSValue, aby można było na niej wywołać CGRectValue.

Wszystko to można osiągnąć za pomocą kombinacji opcjonalnych przypisanie, opcjonalne łańcuchowanie i opcjonalne odlewy:

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
}

Lub w jednym kroku:

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

Aktualizacja dla 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
}

Lub w jednym kroku:

if let keyboardSize = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    // ...
}
 179
Author: Martin R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-18 10:58:18

Dla jeszcze mniej kodu warto spojrzeć na to

To było dla mnie bardzo pomocne. Musisz tylko uwzględnić ograniczenie widoku w kontrolerze widoku i użyć dwóch dodanych obserwatorów. Następnie po prostu użyj następujących metod (przypuszcza się, że tutaj przenosisz widok 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()
                })
            }
        }
    }

I

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() })
  }
} }
 17
Author: Nicholas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-29 07:42:38

Jeśli używasz storyboard, zamiast manipulować samym widokiem, możesz skorzystać z automatycznego układu.

(to jest oczyszczona Wersja odpowiedzi Nicholasa)

Skonfiguruj Centrum powiadomień, aby powiadamiało cię o pojawieniu się i zniknięciu klawiatury:

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)

}

I upewnij się, że usuniesz obserwatorów, gdy już ich nie potrzebujesz:

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

Wewnątrz storyboardu, Ustaw dolne ograniczenie. Stworzyć ujście tego ograniczenie:

Tutaj wpisz opis obrazka

I ustawić stałą właściwości ograniczenia, gdy klawiatura jest pokazana lub ukryta:

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

Teraz, gdy pojawi się lub zniknie klawiatura, autolayout zajmie się wszystkim.

 10
Author: DudeOnRock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-16 04:53:33

To mi pomogło: 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()
 3
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-24 20:21:11

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
}
 3
Author: Barlow Tucker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-01 16:42:46

Możesz użyć tej jednej linii dla swojej linii

var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size
 1
Author: Avinash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-19 09:33:37

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)
}
 1
Author: Kevin Sabbe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-18 17:34:06

Swift 3.0

Oto przykład pobierania rozmiaru klawiatury i używania jej do animowania widoku w górę. W moim przypadku przesuwam UIView zawierający moje pola UITextFields w górę, gdy użytkownik zaczyna pisać, aby mógł wypełnić formularz i nadal zobaczyć przycisk submit na dole.

Dodałem ujście do dolnego ograniczenia przestrzeni widoku, który chciałem animować i nazwałem go nazwanym myViewsBottomSpaceConstraint:

@IBOutlet weak var myViewsBottomSpaceConstraint: NSLayoutConstraint!

Następnie dodałem następujący kod do mojego swift Klasa:

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
Author: mobilecat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-08 16:48:02

Szczegóły

XCode 8.2.1, swift 3

Kod

KeyboardNotifications

import Foundation

class KeyboardNotifications {

    fileprivate var _isEnabled: Bool
    fileprivate var notifications:  [KeyboardNotificationsType]
    fileprivate 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(KeyboardNotifications.keyboardWillShow(notification:))

            case .willHide:
                return #selector(KeyboardNotifications.keyboardWillHide(notification:))

            case .didShow:
                return #selector(KeyboardNotifications.keyboardDidShow(notification:))

            case .didHide:
                return #selector(KeyboardNotifications.keyboardDidHide(notification:))

            }
        }

        var notificationName: NSNotification.Name {
            switch self {

            case .willShow:
                return .UIKeyboardWillShow

            case .willHide:
                return .UIKeyboardWillHide

            case .didShow:
                return .UIKeyboardDidShow

            case .didHide:
                return .UIKeyboardDidHide
            }
        }
    }
}

// MARK: - isEnabled

extension KeyboardNotifications {

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

    var isEnabled: Bool {
        set {
            if newValue {

                for notificaton in notifications {
                    addObserver(type: notificaton)
                }
            } else {
                NotificationCenter.default.removeObserver(self)
                print("Keyboard notifications deinited")
            }
            _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)
    }
}

KeyboardNotificationsDelegate

import Foundation

@objc
protocol KeyboardNotificationsDelegate {

    @objc optional func keyboardWillShow(notification: NSNotification)
    @objc optional func keyboardWillHide(notification: NSNotification)
    @objc optional func keyboardDidShow(notification: NSNotification)
    @objc optional func keyboardDidHide(notification: NSNotification)
}

Użycie

 class ViewController: UIViewController {
      private var keyboardNotifications: KeyboardNotifications!
      override func viewDidLoad() {
           super.viewDidLoad()
           ...
            keyboardNotifications = 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) {
           ...
    }

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

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

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

Pełna Próbka

import UIKit

class ViewController: UIViewController {

    private var keyboardNotifications: KeyboardNotifications!
    private var textField = UITextField(frame: CGRect(x: 40, y: 40, width: 200, height: 30))

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(textField)

        // when you will tap on view (background) the keyboard will hide
        // read about view.disableKeybordWhenTapped here: http://stackoverflow.com/a/42187286/4488252
        view.disableKeybordWhenTapped = true

        keyboardNotifications = 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")
        let userInfo = notification.userInfo as! [String: NSObject]
        let keyboardFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as! CGRect
        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")
    }
}

Wynik

Tutaj wpisz opis obrazka

Log

Tutaj wpisz opis obrazka

 0
Author: Vasily Bodnarchuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-06 17:20:54

Dla xamarin, można użyć 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
Author: marcel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-19 19:45:23