Swift'de userInfo'dan klavye boyutunu alma


82

Klavye göründüğünde görünümümü yukarı taşımak için bazı kodlar eklemeye çalışıyorum, ancak Objective-C örneklerini Swift'e çevirmeye çalışırken sorun yaşıyorum. Biraz ilerleme kaydettim, ancak belirli bir çizgide sıkıştım.

Bunlar takip ettiğim iki öğretici / soru:

Swift http://www.ioscreator.com/tutorials/move-view-when-keyboard-appears kullanılarak Tuş Takımı göründüğünde UIViewController içeriği yukarı doğru nasıl taşınır

İşte şu anda sahip olduğum kod:

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

Şu anda bu satırda bir hata alıyorum:

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

Birisi bana bu kod satırının ne olması gerektiğini bildirebilirse, gerisini kendim çözmeliyim.

Yanıtlar:


186

Hattınızda bazı sorunlar var:

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
  • notification.userInfoisteğe bağlı bir sözlük döndürür [NSObject : AnyObject]?, bu nedenle değerlerine erişilmeden önce sarmalanması gerekir.
  • Objective-C NSDictionary, bir Swift yerel Sözlüğü ile eşleştirilmiştir, bu nedenle dict[key]değerlere erişmek için sözlük alt simge sözdizimini ( ) kullanmanız gerekir .
  • Onu NSValuearayabilmeniz CGRectValueiçin değer atılmalıdır .

Tüm bunlar, isteğe bağlı atama, isteğe bağlı zincirleme ve isteğe bağlı alçıların bir kombinasyonu ile elde edilebilir:

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
}

Veya tek adımda:

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) Güncellemesi:

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
}

Veya tek adımda:

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

Swift 5 Güncellemesi (Xcode 11.6):

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

Bunun keyboardFrameEndUserInfoKeyyerine keyboardFrameBeginUserInfoKey, klavye eski iOS cihazlarda ilk görüntüden sonra ilk oluşturma yüksekliğini değiştirdiği için kullanmanızı öneririm .


@MartinR Yanlış gönderiye yorum yaptığım için üzgünüm :) üzgünüm
Lamour

Merhaba, bildirimlerle klavye boyutunu almaya çalışıyorum ancak çalışmasını sağlayamıyorum. Gözlemciyi viewDidload'a ekliyorum (viewWillAppear'ı da denedim) NSNotificationCenter.defaultCenter (). AddObserver (self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil) Ancak yöntem çağrılmıyor. Gerçek bir cihaz ve simülatörde denedim. Herhangi bir tavsiye? Çok teşekkür ederim.
theMouse

"Tek adımda" yanıtta cgRectValue var, ancak CGRectValue olmalı
Vladimirs Matusevics

@krotov Cevabın ilk kısmı Swift 2 için, ikinci kısmı Swift 3 için. Bu özellik, bu sürümler arasında yeniden adlandırıldı.
Martin R

1
Klavye çerçevesi değiştiğinde (tahmini etkin veya iOS 9 veya sonrası için emoji klavyesine geç) durum için UIKeyboardFrameBeginUserInfoKey yerine UIKeyboardFrameEndUserInfoKey kullanmanın daha iyi olduğunu düşünüyorum
crcalin

18

Hatta daha az kodu için dikkate bakarak BU

Bana gerçekten yardımcı oldu. Görünüm kısıtlamasını görünüm denetleyicisine eklemeniz ve eklediğiniz iki gözlemciyi kullanmanız yeterlidir. Ardından, aşağıdaki yöntemleri kullanın (burada bir tableView'i taşıdığınız varsayılır)

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

ve

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
Bu cevabı başka bir yerde görene kadar alamadım, burada tableViewBottomConstraint'in Xib için bir çıkış olduğunu anladım. Sonra bunun mükemmel cevap olduğu anlaşıldı! (Otomatik düzen kullanıyorsanız)
Joris van Liempd iDeveloper

@JorisvanLiempd Evet, otomatik düzen kullanıyorum. Sana yardım etmesi iyi.
Nicholas

Görünüşe göre animasyon, animasyon bloğu olmadan ücretsiz geliyor. bu cevapta klavye eğrisini ve süresini zaten takip etmiyor.
AmitP

11

Görünümün kendisini değiştirmek yerine film şeridi kullanıyorsanız, otomatik mizanpajdan yararlanabilirsiniz.

(Bu, Nicholas'ın Cevabının temizlenmiş bir sürümüdür)

Klavyenin görünümü ve kaybolması konusunda sizi bilgilendirmek için bildirim merkezini ayarlayın:

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)

}

Ve artık ihtiyacınız kalmadığında gözlemcileri kaldırdığınızdan emin olun:

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

Film şeridinin içinde alt sınırlamayı ayarlayın. Bu kısıtlamanın bir çıkışını oluşturun:

görüntü açıklamasını buraya girin

ve klavye gösterildiğinde veya gizlendiğinde kısıtlamanın sabit özelliğini ayarlayın:

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

Artık, klavye göründüğünde veya kaybolduğunda, otomatik düzen her şeyi halledecektir.


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
    }

Hızlı 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
}

Teşekkürler, bana çok yardımcı oluyor!
javimuu

3

Bu bana yardımcı oldu: 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

Hattınız için bu tek satırı kullanabilirsiniz

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

3
Bu sözlükten klavye çerçevesini zorla açmak güvenli değildir. Orada olamazdım.
Adama

1

Swift 3: GÜNCELLEME

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'dan Klavye Yüksekliği

Klavyedeki verileri kullanarak bir kısıtlamayı veya başka herhangi bir değeri klavyenin boyutuna büyütebilir veya küçültebilirsiniz Bildirimleri Gösterecek / Gösterecek / Gizleyebilirsiniz.

Düzen Kısıtlamasıyla

Bu minimum kod, klavyenin boyutuna bağlı olarak bir kısıtlama göstereceğini ve güncelleyeceğini bildirmek için kaydeder.

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

Aynı şekilde bu, klavyenin boyutuna göre bir kaydırma görünümünün ek içeriğini günceller.

@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

Detaylar

  • Xcode Sürüm 11.1 (11A1027), iOS 13, Swift 5

Çözüm

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

Kullanım

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

Tam Örnek

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

Sonuç

görüntü açıklamasını buraya girin

Kayıt

görüntü açıklamasını buraya girin


0

Swift 3.0

Aşağıda, klavye boyutunu alma ve bir görünümü yukarı doğru canlandırmak için kullanma örneği verilmiştir. Benim durumumda, bir kullanıcı yazmaya başladığında UITextFields'ımı içeren bir UIView'ı yukarı doğru hareket ettiriyorum, böylece bir formu doldurabilir ve yine de alttaki gönder düğmesini görebilir.

Canlandırmak istediğim görünümün alt alan kısıtlamasına bir çıkış ekledim ve adını şu şekilde adlandırdım myViewsBottomSpaceConstraint:

@IBOutlet weak var myViewsBottomSpaceConstraint: NSLayoutConstraint!

Daha sonra swift sınıfıma aşağıdaki kodu ekledim:

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 için c # 6 kullanabilirsiniz

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

içinde Swift 4.2 Eğer UIResponder.keyboardFrameEndUserInfoKey kullanabilirsiniz

guard let userInfo = notification.userInfo , let keyboardFrame:CGRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect  else { return  }```
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.