问题
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!
回答1:
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];
回答2:
keyboardWillShow:
NSDictionary *info = [notification userInfo];
CGRect keyboardFrame = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval duration = [info[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [info[UIKeyboardAnimationCurveUserInfoKey] integerValue];
[self layoutIfNeeded];
[UIView animateWithDuration:duration delay:0 options:(curve << 20) animations:^{
[self.keyboardConstraint setConstant:keyboardFrame.size.height];
[self layoutIfNeeded];
} completion:nil];
来源:https://stackoverflow.com/questions/22260711/synchronizing-animations-in-keyboardwillshow-keyboardwillhide-hardware-keyboa