I\'m looking for a way to slide the keyboard into view from the right, like what happens in the Contacts application when you edit a note.
My problem is that when I
In iOS 7, calling becomeFirstResponder
on _textView
in viewDidLayoutSubviews
works.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[_textView becomeFirstResponder];
}
Note: Doing it in viewWillLayoutSubviews
also works.
Read the discussion in the docs for becomeFirstResponder.
You may call this method to make a responder object such as a view the first responder. However, you should only call it on that view if it is part of a view hierarchy. If the view’s
window
property holds aUIWindow
object, it has been installed in a view hierarchy; if it returnsnil
, the view is detached from any hierarchy.
When using a navigation controller to push your custom view controller onscreen, self.view.window
is still nil
by the time either viewDidLoad
or viewWillAppear:
is called. So, _textView.window
is also nil
in the same methods, since _textView
is a subview of self.view
, i.e., they're both in the same window. No matter how you present your custom view controller, self.view.window
(and thus _textView.window
) is also nil
in initWithNibName:bundle:
. self.view.window
is set by the time viewDidAppear:
is called, but that's too late because by that time, the navigation controller has already completed the animation of pushing the view onscreen.
self.view.window
is also set by the time either viewWillLayoutSubviews
or viewDidLayoutSubviews
is called and these methods are called before the push animation of the navigation controller begins. So, that's why it works when you do it in either of those methods.
Unfortunately, viewWillLayoutSubviews
and viewDidLayoutSubviews
get called a lot more than just on the initial navigation controller push. But, navigationController:willShowViewController:
and willMoveToParentViewController:
get called too soon (after viewDidLoad
but before self.view.window
is set) and navigationController:didShowViewController:
and didMoveToParentViewController:
get called too late (after the push animation).
The only other way I can think of doing it is to somehow observe the window
property of _textView
so that you get notified when it changes, but I'm not sure how to do that since window
is readonly
.
In iOS 7 (or any version before) you can make a simple thing in loadView, viewDidLoad or viewWillAppear
[yourTextView performSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
In this case you will get left-to-right appearance of the keyboard aligned with the motion of pushing view controller.
You could try sending the becomeFirstResponder message to the new view controller before you push it onto the stack. For example:
-(void)functionWhereYouPushTheNewViewController {
yourNewViewController *newVC = [[yourNewViewController alloc] init];
[newVC.yourTextView becomeFirstResponder];
[self.navigationController pushViewController:newVC animated:YES];
}
I have found that changing animations on things like they keyboard is pretty tough though, and if you read the Human Interface Guidelines Apple makes it pretty clear that they want certain things to act in certain ways, all the time. There are ways to change the behaviors of certain animations but they often involve undocumented API calls and are grounds for rejection from the app store. It would be a violation of HIG to have pushed views slide up from the bottom, for example.
Hope this helps.
All you need to do is tell the text view in question to become the first responder in the viewDidLoad
method of the view controller you're pushing onto the navigation stack:
override func viewDidLoad() {
super.viewDidLoad()
someTextView.becomeFirstResponder()
}
This works in iOS 8. The keyboard slides in from the right along with the view.
For iOS 7 I've found the following solution to work the best for me:
-Import UIResponder-KeyboardCache to your project.
-Add [UIResponder cacheKeyboard:YES];
to the viewDidLoad
of the view before the keyboard view. It might be better to do this immediately when the application loads or during a time convenient when you can afford it (during an HTTP request, for example). In most cases, simply in the view before is sufficient.
-Add the following to the viewDidLoad
of the keyboard view.
dispatch_async(dispatch_get_main_queue(), ^{
[_textField becomeFirstResponder];
});
To explain, this will preload the keyboard view, which will remove the delay from the first call of the keyboard view. Calling becomeFirstResponder
on the text field in the main queue causes it to slide in with the view instead of animating upward before the view slides in.