Synchronizing Animations in keyboardWillShow keyboardWillHide -- Hardware Keyboard & Virtual Keyboard Simultaneously

animation, ios, objective-c, uikeyboard, uiviewanimation

Solution

Since the animation curve Apple sends you in the keyboard notification does not have a corresponding UIViewAnimationOption bit, you need to drop down to old-school non-block animations and use the curve directly:

NSTimeInterval duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [note.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
[UIView beginAnimations:@"SomeAnimationID" context:NULL];
[UIView setAnimationCurve:curve];
[UIView setAnimationDuration:duration];
// Animation code
[UIView commitAnimations];

Problem

Preamble So I have an application featuring a chat section, and I'm synchronizing the animation of the keyboard hiding and showing with the rise and fall of the chat input. Here's the code I'm using: SHOW: ``` - (void) keyboardWillShow:(NSNotification *)note { NSDictionary *keyboardAnimationDetail = [note userInfo]; UIViewAnimationCurve animationCurve = [keyboardAnimationDetail[UIKeyboardAnimationCurveUserInfoKey] integerValue]; CGFloat duration = [keyboardAnimationDetail[UIKeyboardAnimationDurationUserInfoKey] floatValue]; NSValue* keyboardFrameBegin = [keyboardAnimationDetail valueForKey:UIKeyboardFrameBeginUserInfoKey]; CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue]; // working for hardware keyboard //UIViewAnimationOptions options = (UIViewAnimationOptions)animationCurve; // working for virtual keyboard UIViewAnimationOptions options = (animationCurve << 16); [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ textView.frame = CGRectMake(0, self.view.bounds.size.height - keyboardFrameBeginRect.size.height, self.view.bounds.size.width, -40); } completion:nil]; } ``` HIDE: ``` - (void) keyboardWillHide:(NSNotification *)note { NSDictionary *keyboardAnimationDetail = [note userInfo]; UIViewAnimationCurve animationCurve = [keyboardAnimationDetail[UIKeyboardAnimationCurveUserInfoKey] integerValue]; CGFloat duration = [keyboardAnimationDetail[UIKeyboardAnimationDurationUserInfoKey] floatValue]; // hardware keyboard //UIViewAnimationOptions options = (UIViewAnimationOptions)animationCurve; // virtual keyboard UIViewAnimationOptions options = (animationCurve << 16); [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ textView.frame = CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, -40); } completion:nil]; } ``` This works great with the virtual keyboard, but if keyboardWillShow: or keyboardWillHide: is called as a result of disconnecting or connecting a hardware keyboard, the animation lags. I can fix this by changing the UIViewAnimationOptions Replace: ``` // Works with virtual keyboard UIViewAnimationOptions options = (animationCurve << 16); ``` With: ``` // working for firstResponder keyboard UIViewAnimationOptions options = (UIViewAnimationOptions)animationCurve; ``` But with this, now the virtualKeyboard animation lags I realize that hardware keyboard animations aren't very common and it's perhaps not the most important issue, but I like everything to just work! Examples VirtualKeyboard w/ (animationCurve << 16) -- WORKING VirtualKeyboard w/ (UIViewAnimationOptions)animationCurve -- BROKEN HardwareKeyboard w/ (animationCurve << 16) -- BROKEN HardwareKeyboard w/ (UIViewAnimationOptions)animationCurve -- WORKING Notes To simulate hardware keyboard in simulator cmd + shft + k Yes, this is replicable on real device. In case you want it, here's the rest of my code, just for replication purposes ADD TEXT VIEW ``` textView = [UITextView new]; textView.layer.borderWidth = 10; textView.layer.borderColor = [UIColor blackColor].CGColor; textView.frame = CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, -40); [self.view addSubview:textView]; UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init]; [tap addTarget:self action:@selector(handleTap:)]; [self.view addGestureRecognizer:tap]; // OBSERVE KEYBOARD [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; ``` HANDLE TAP: ``` - (void) handleTap:(UITapGestureRecognizer *)tap { NSLog(@"tapped"); [textView resignFirstResponder]; } ``` The Question: What is going on here, and is there a good way to get consistent animation regardless of virtual / hardware keyboard? I realize this is long, thank you for reading!

Original source

Related problems