What is the animation speed of the keyboard appear

2019-03-23 08:34发布

问题:

The following is an animation for a textField and toolBar which move upward when the keyboard appears.

    baseConstraint.constant = 211
    self.view.setNeedsUpdateConstraints()

    UIView.animateWithDuration(0.30, animations: {
        self.view.layoutIfNeeded()
        })

It is close but not quite identical. How would you modify the above animation?

Edit:

Here is the final code using the answer below!

   func keyboardWillShow(aNotification: NSNotification)    {

        let duration = aNotification.userInfo.objectForKey(UIKeyboardAnimationDurationUserInfoKey) as Double
        let curve = aNotification.userInfo.objectForKey(UIKeyboardAnimationCurveUserInfoKey) as UInt

        self.view.setNeedsLayout()
        baseConstraint.constant = 211
        self.view.setNeedsUpdateConstraints()

        UIView.animateWithDuration(duration, delay: 0, options: UIViewAnimationOptions.fromMask(curve), animations: {
        self.view.layoutIfNeeded()
        }, completion: {
        (value: Bool) in println()
        })
}

回答1:

You can get the animation duration and the animation curve from the userInfo dictionary on the keyboardWillShow: notifications.

First register for the notification

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

Then get the values from the notifications userInfo keys.

- (void)keyboardWillShow:(NSNotification*)notification {
    NSNumber *duration = [notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSNumber *curve = [notification.userInfo objectForKey: UIKeyboardAnimationCurveUserInfoKey];

   // Do stuff with these values.
}

There are a lot more of these keys, and you can also get them from the UIKeyboardWillDismiss notification.

This functionality is available all the way back to iOS 3.0 :D

Heres the docs:

https://developer.apple.com/library/ios/documentation/uikit/reference/UIWindow_Class/UIWindowClassReference/UIWindowClassReference.html#//apple_ref/doc/constant_group/Keyboard_Notification_User_Info_Keys

Let me know if you need help making it work.

Swift Version:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)


func keyboardWillShow(aNotification: NSNotification)    {

        let duration = aNotification.userInfo.objectForKey(UIKeyboardAnimationDurationUserInfoKey) as NSNumber
        let curve = aNotification.userInfo.objectForKey(UIKeyboardAnimationCurveUserInfoKey) as NSNumber
}


回答2:

The answer with the variable duration is right and work iOS 3 to 8, but with the new version of Swift, the answer's code is not working anymore. Maybe it is a mistake on my side, but I have to write:

let duration = aNotification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as Double
let curve = aNotification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as UInt

self.view.setNeedsLayout()
//baseConstraint.constant = 211
self.view.setNeedsUpdateConstraints()

UIView.animateWithDuration(duration, delay: 0.0, options: UIViewAnimationOptions(curve), animations: { _ in
    //self.view.layoutIfNeeded()
}, completion: { aaa in
    //(value: Bool) in println()
})

Looks like objectForKey is not working anymore and conversion is more strict.



回答3:

swift3

    let duration = noti.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
    let curve = noti.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber

    self.view.setNeedsLayout()

    UIView.animate(withDuration: TimeInterval(duration), delay: 0, options: [UIViewAnimationOptions(rawValue: UInt(curve))], animations: {
      self.view.layoutIfNeeded()
    }, completion: nil)


回答4:

Swift 4 update, iOS 11+

Register for the notification first in a view's lifecycle method :

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

Then in keyBoardWillShow method :

@objc func keyBoardWillShow(notification: NSNotification) {
    guard let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double else {return}
    print(duration) // you got animation's duration safely unwraped as a double
}

Finally, don't forget to remove observer in deinit method :

deinit {
    NotificationCenter.default.removeObserver(self)
}


回答5:

Firstly, the selected answer is the right way to go.

More can be provided here is what the animation really is. If you print all CAAnimations in the UIViewAnimation block, you'll find that it's a CASpringAnimation when setting the animation curve to the one provided in keyboard notification. The duration is 0.5, and other parameters are:

let ani = CASpringAnimation(keyPath: someKey)
ani.damping = 500
ani.stiffness = 1000
ani.mass = 3
ani.duration = 0.5

The code above can reproduce the animation precisely.

Once animation curve is set to the keyboard one, UIView animation will ignore the duration in the parameter. (If you really want to change the duration, adjust the mass value.)



回答6:

// first of all declare delegate in your class UITextFieldDelegate

//Place at the top of the view controller

 // ****************** Keyboard Animation ***************
var animateDistance = CGFloat()
struct MoveKeyboard {
    static let KEYBOARD_ANIMATION_DURATION : CGFloat = 0.3
    static let MINIMUM_SCROLL_FRACTION : CGFloat = 0.2;
    static let MAXIMUM_SCROLL_FRACTION : CGFloat = 0.8;
    static let PORTRAIT_KEYBOARD_HEIGHT : CGFloat = 216;
    static let LANDSCAPE_KEYBOARD_HEIGHT : CGFloat = 162;
}
//

//Copy and pest textfields delegate method in you class

func textFieldDidBeginEditing(textField: UITextField) {
    let textFieldRect : CGRect = self.view.window!.convertRect(textField.bounds, fromView: textField)
    let viewRect : CGRect = self.view.window!.convertRect(self.view.bounds, fromView: self.view)
    let midline : CGFloat = textFieldRect.origin.y + 0.5 * textFieldRect.size.height
    let numerator : CGFloat = midline - viewRect.origin.y - MoveKeyboard.MINIMUM_SCROLL_FRACTION * viewRect.size.height
    let denominator : CGFloat = (MoveKeyboard.MAXIMUM_SCROLL_FRACTION - MoveKeyboard.MINIMUM_SCROLL_FRACTION) * viewRect.size.height
    var heightFraction : CGFloat = numerator / denominator

    if heightFraction > 1.0 {
        heightFraction = 1.0
    }
    let orientation : UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown) {
        animateDistance = floor(MoveKeyboard.PORTRAIT_KEYBOARD_HEIGHT * heightFraction)
    } else {
        animateDistance = floor(MoveKeyboard.LANDSCAPE_KEYBOARD_HEIGHT * heightFraction)
    }

    var viewFrame : CGRect = self.view.frame
    viewFrame.origin.y -= animateDistance
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))
    self.view.frame = viewFrame
    UIView.commitAnimations()
}
func textFieldDidEndEditing(textField: UITextField) {
    var viewFrame : CGRect = self.view.frame
    viewFrame.origin.y += animateDistance

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)

    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))

    self.view.frame = viewFrame

    UIView.commitAnimations()

}
func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}


回答7:

I'd like to point out something that tripped me up while solving this issue. I needed the size of the keyboard due to the new "quickype" view and its ability to show/hide (iOS8 only). This is how I ended up solving it:

- (void)keyboardWillChangeFrame:(NSNotification *)notification {
    NSValue *value = notification.userInfo[UIKeyboardFrameEndUserInfoKey];
    self.keyboardFrame = [value CGRectValue];

    NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    [UIView animateWithDuration:duration animations:^{
    //ANIMATE VALUES HERE
}];

}



回答8:

//--------------------------------------------------------------
// MARK: -
// MARK: - UITextFieldDelegate
//--------------------------------------------------------------
//To trigger event when user types in fields
//right click in IB and choose EditingChanged >> textField_EditingChanged
//NOTE IF KEYBOARD NOT SHOWING IN SIMULATOR and no view appearing ITS TURNED OFF BY DEFAULT SO YOU CAN TYPE WITH YOUR MAC KEYBOARD - HIT CMD+K or Simulator > Menu > Toggle Software Keyboard...

@IBAction func textField_EditingChanged(textField: UITextField) {
    //if more than one search
    if(textField == self.textFieldAddSearch){
        appDelegate.log.error("self.textFieldAddSearch: '\(self.textFieldAddSearch.text)'")
        if textField.text == ""{

        }else{
            callJSONWebservices(textField.text)
        }
    }else{
        appDelegate.log.error("textFieldDidBeginEditing: unhandled textfield")
    }
}

//TWO WAYS TO HIDE THE VIEW
//textFieldShouldReturn
//buttonCancel_Action

//USER HIT RETURN BUTTON ON keyboard >> resignFirstResponder >> triggers  keyboardWillHide
func textFieldShouldReturn(textField: UITextField)-> Bool{

    //triggers keyboardWillHide: which also fades out view
    self.textFieldAddSearch.resignFirstResponder()

    return false
}

//--------------------------------------------------------------
// MARK: -
// MARK: - KEYBORAD
//--------------------------------------------------------------
private func subscribeToKeyboardNotifications() {

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

private func unsubscribeFromKeyboardNotifications() {

    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {

    if let userInfo = notification.userInfo {
        if let heightKeyboard = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().height {
            if let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue {

                self.viewAddNewSearchResults.alpha = 0.0
                self.viewAddNewSearchResults.hidden = false
                if let curve = userInfo[UIKeyboardAnimationDurationUserInfoKey]?.integerValue {

                    appDelegate.log.info("keyboardWillShow: duration:\(duration)")

                    UIView.animateWithDuration(duration, delay:0.0, options: .CurveEaseInOut,
                        animations: {
                            //self.view.frame = CGRectMake(0, 0, Geo.width(), Geo.height() - height)
                            self.viewAddNewSearchResults_BottomConstraint.constant = heightKeyboard;
                            self.viewAddNewSearchResults.alpha = 1.0
                        },
                        completion: nil)
                }
            }
        }
    }

}

func keyboardWillHide(notification: NSNotification) {

    if let userInfo = notification.userInfo {
        if let heightKeyboard = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().height {
            if let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue {
                if let curve = userInfo[UIKeyboardAnimationDurationUserInfoKey]?.integerValue {

                    appDelegate.log.info("keyboardWillHide: duration:\(duration)")

                    UIView.animateWithDuration(duration, delay:0.0, options: .CurveEaseInOut,
                        animations: {
                            self.viewAddNewSearchResults_BottomConstraint.constant = 0;
                            self.viewAddNewSearchResults.alpha = 0.0
                        },
                        completion: nil)
                }
            }
        }
    }
}

//Add button shows search result panel below search text fields
//just set focus in the textField
//then the keyboardWillShow will fade in the view and resize it to fit above the keyboard
//and match fade in duration to animation of keyboard moving up
@IBAction func buttonAdd_Action(sender: AnyObject) {

    //triggers keyboardWillHide: which also fades out view
    self.textFieldAddSearch.resignFirstResponder()
}

//TWO WAYS TO HIDE THE VIEW
//textFieldShouldReturn
//buttonCancel_Action

//Cancel on the search results - just resignFirstResponder >> triggers keyboardWillHide: which also fades out view
@IBAction func buttonCancel_Action(sender: AnyObject) {
    //triggers keyboardWillHide: which also fades out view
    self.textFieldAddSearch.resignFirstResponder()
}


回答9:

Swift 4

 NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)

 func keyboardWillShow(notification: NSNotification) {
      let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey]
      print("duration",duration)
 }