In my keyboard extension, there is one particular viewController which I would like to cause the keyboard to increase in height. Before presenting this viewController, the main UIInputViewController calls this method on itself, passing a value of 400.0:
- (void)setKeyboardHeight:(CGFloat)height {
if (self.heightConstraint) {
[self.view removeConstraint:self.heightConstraint];
self.heightConstraint = nil;
}
self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:height];
[self.view addConstraint:self.heightConstraint];
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
}
The height of the keyboard does change to the specified value, but it isn't animated. Is this impossible to accomplish, or am I just using the wrong method in a keyboard extension?
Here's one solution I came up with. Call animateKeyboardHeightTo: speed:
and pass in the height you want the keyboard to change to as targetHeight
and the number of points per ms as speed
, and the keyboard will increase or decrease to the specified height. I tried to use duration rather than speed, increase by one point per iteration and calculate the duration for dispatch_after
so that the whole animation would occur within the specified duration, but I couldn't get dispatch_after
to execute fast enough. I don't know if it is simply not sufficiently precise, or if it cannot execute at less than 1 second intervals, but this was the only solution I could come up with.
If you want to toggle between sizes, you can store self.view.frame.size.height
in a property before making the initial call to animateKeyboardHeightTo: speed:
, and then call this method again and pass in the stored height to restore the keyboard to its initial height.
- (void)animateKeyboardHeightTo:(CGFloat)targetHeight speed:(CGFloat)speed {
CGFloat initialHeight = self.view.frame.size.height;
if (targetHeight < initialHeight) {
speed = -speed;
}
[self setKeyboardHeight:initialHeight];
[self increaseKeyboardHeightToTargetHeight:targetHeight speed:speed];
}
- (void)increaseKeyboardHeightToTargetHeight:(CGFloat)targetHeight speed:(CGFloat)speed {
CGFloat currentHeight = self.heightConstraint.constant;
CGFloat nextHeight = currentHeight + speed;
if ((speed > 0 && nextHeight > targetHeight) || (speed < 0 && nextHeight < targetHeight)) {
nextHeight = targetHeight;
}
[self setKeyboardHeight:nextHeight];
if ((speed > 0 && nextHeight < targetHeight) || (speed < 0 && nextHeight > targetHeight)) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
[self increaseKeyboardHeightToTargetHeight:targetHeight speed:speed];
});
}
}
- (void)setKeyboardHeight:(CGFloat)height {
[self removeHeightConstraint];
[self addHeightConstraintWithHeight:height];
}
- (void)removeHeightConstraint {
if (self.heightConstraint) {
[self.view removeConstraint:self.heightConstraint];
self.heightConstraint = nil;
}
}
- (void)addHeightConstraintWithHeight:(CGFloat)height {
self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:height];
[self.view addConstraint:self.heightConstraint];
}