Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animating an `inputView` Keyboard Transition

UITextField has an inputView property that can be used to specify a custom keyboard. Clearing this to nil provides the default keyboard.

If the UITextField is the first responder, no change occurs on setting inputView, but by calling [textField reloadInputView] the keyboard change will happen immediately.

I'd like to be able to switch between two different input approaches. The interface to trigger this will be a UISegmentedView installed as the UITextField's inputAccessoryView.

I've got this working, but the transition is very abrupt. Partly because the spinner and keyboard I transition between have different sizes on the iPad.

I've found that is I wrap an animation block around reloadInputView, I will get a smooth animation between the two keyboard's view frames. Unfortunately there is a visual judder because the transition is not animated:

[UIView animateWithDuration: 0.3 animations:^()
{
    [firstResponder reloadInputViews];
}];

Alternatively, if I wrap the reload in a transition, I can get a nice cross fade, but I don't get smooth frame changes:

[UIView transitionWithView: keyboardWindow
                  duration: 0.3
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(){ [firstResponder reloadInputViews]; }
                completion: nil];

(In the second code block I obtained keyboardWindow from self.window because this view is installed as the UITextField's inputAccessoryView which is ultimately nested under the keyboard's window.)

What I'd like is to animate and transition the input view reload. I tried placing reload in a transition in an animation, and I also tried placing the reload in an animation in a transition – neither seemed to help.

Any ideas? Thanks!

like image 682
Benjohn Avatar asked Jan 14 '15 17:01

Benjohn


2 Answers

You can invoke resignFirstResponder to make the input view disappear and then invoke becomeFirstResponder, after a delay, to make the keyboard appear and vice versa.

The following sets to inputView after resigning the normal keyboard.

let delayTime = dispatch_time(DISPATCH_TIME_NOW,Int64(1 * (NSEC_PER_SEC/3)))

textField.resignFirstResponder()

dispatch_after(delayTime, dispatch_get_main_queue()) {
     self.textField.inputView = currentInputView
     self.textField.becomeFirstResponder()
} 

This sets to keyboard.

dispatch_after(delayTime, dispatch_get_main_queue()) {
     self.textField.inputView = nil
     self.textField.becomeFirstResponder()
}
like image 128
rakeshbs Avatar answered Oct 20 '22 00:10

rakeshbs


I'm able to successfully animate changes to an inputView without any glitches by:

  1. Adding the new inputView as a subview of the existing inputView and then
  2. Switching the UIControl's inputView to the custom inputView after your choice of animation is complete.

As an example, here's how to quickly fade in a custom inputView:

//start the view as invisible
_customInputView.alpha = 0.0f;

//add the custom inputView as a subview of the existing inputView
[self.inputView addSubview:_customInputView];

//animate the opacity change
[UIView animateWithDuration:0.25f 
                      delay:0.0f
                    options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         _customInputView.alpha = 1.0f;
                     } completion:^(BOOL finished) {
                         //switch the UIControl's inputView
                         self.inputView = _customInputView;
                     }];
like image 39
adamup Avatar answered Oct 20 '22 01:10

adamup