We have a view open with keyboard shown , but when the back button clicked , the view slide out from right while the keyboard will slide only when the view disappeared.
if we call resignFirstResponder at viewwilldisappear, the view slide to the right while keyboard slide down at same time.
Is it possible to let the keyboard slide out with the view?
I have tested this and it works in iOS 5.1, however, I don't think this is recommended behaviour.
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows])
if ([[keyboardWindow description] hasPrefix:#"<UITextEffectsWindow"]) {
NSLog(#"%#", [keyboardWindow description]);
[UIWindow beginAnimations:#"fadeKeyboard" context:nil];
keyboardWindow.frame = CGRectMake(keyboardWindow.frame.origin.x + keyboardWindow.frame.size.width, keyboardWindow.frame.origin.y, keyboardWindow.frame.size.width, keyboardWindow.frame.size.height);
[UIWindow commitAnimations];
}
You can also use a notification UIKeyboardWillHideNotification to detect when the keyboard is going to hide, or just use the above code manually.
There is no standard way to do what you want, but...
Basically, keyboard is just a view, presented in it's own UIWindow on top of all your other windows.
So, theoretically, what you need to do is to find keyboard view and move it in desired direction. I think you should use transform property and don't mess up with frame.
Class keyboardClass = NSClassFromString(#"UIPeripheralHostView");
for ( UIWindow *window in [[UIApplication sharedApplication] windows] ) {
for ( UIView *subview in window.subviews ) {
if ( [subview isKindOfClass:keyboardClass] ) {
// that's keyboard
}
}
}
Edited:
If you're talking about UINavigationController and it's default slide animations during push / pop, then, you just need to invoke resignFirstResponder in viewDidDisappear and becomeFirstResponder in viewWillAppear on your text view. That way your keyboard will slide along with your view.
Try sticking resignFirstresponder in the viewDidDisappear method instead.
**Set notificatins and use these methods.....Hope it solve problem:
First of all set your whole view in scrollView**
-(void)keyboardDidHide:(NSNotification *)notif
{
NSTimeInterval duration = 0.4;
[UIView animateWithDuration:duration animations:
^{
scrollView.contentSize=CGSizeMake(320,scrollOriginalFrame.size.height);
}];
keyboardVisible=NO;
}
-(void)keyboardDidShow:(NSNotification *)notif
{
scrollView.contentSize=CGSizeMake(self.view.frame.size.width, scrollOriginalFrame.size.height+235);
NSTimeInterval duration = 0.4;
[UIView animateWithDuration:duration animations:
^{
[scrollView setContentOffset:CGPointMake(0,162) animated:YES];
}];
keyboardVisible=YES;
}
**In viewDidLoad() add this**
//keyboard
scrollOriginalFrame=self.view.frame;
scrollOriginalFrame.size.height-=103;
scrollView.contentSize=scrollOriginalFrame.size;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardWillHideNotification object:nil];
keyboardVisible=NO;
Related
I read many post here about this topic, but I wasn't able to find an answer to my question, so, hope you won't be bored about another UIKeyboard post :-)
In my view controller's implementation I added self as an observer for the two notifications UIKeyboardWillShowNotification and UIKeyboardWillHideNotification, passing the selectors keyboardWillShow: and keyboardWillHide: to handle to notifications. As I touch a UITextField, the keyboardWillShow: method is called but when I press a "Done" button (which dismisses the keyboard) the keyboardWillHide: method is not called.
Really, I'd like to make my UITextField show a keyboard with the "hide button" on the bottom right of the keyboard, but I wasn't able to find the right keyboard type. Maybe I need to set the textfield retuntype to "...Done". In that way I saw that "return" key turns to "done".
So I set a toolbar to be my UITextField's inputAccessoryView, so now I can show a standard keyboard with a tool bar above with the "Done" button. As a user touches that button, I hide the keyboard with the resignFirstResponder method.
The strange thing is that when I call resignFirstResponder, the UIKeyboardWillHideNotification isn't posted; at least the keyboardWillHide: method is not called.
What do you suggest to me? I really wanted to display a keyboard with the small button with the down arrow to hide the keyboard, but also this solution could be right, but I'd like to resize the view and to do this I need to observer UIKeyboardWillHideNotification.
Thank you very much for help...
(ADDED:)
In viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:[[self view] window]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:[[self view] window]];
I took these declarations from one of "yours" post :-) But the willShow works...
The action of the "Done" button that's in the UIToolbar that's assigned to be the inputAccessoryView of my text field is:
-(void)keyboardDone {
[msgTextField resignFirstResponder];
CLOSED:
OK! When a developer is stupid... it is stupid :-) :-)
This is my corrected willHide method:
-(void)keyboardWillHide:(NSNotification*)n {
NSDictionary* userInfo;
CGSize keyboardSize;
CGRect viewFrame;
/* This was the bad guy :) I forgot to delete it
* after I previously copied the willShow method that
* checks if keyboard is already shown (if so returns).
*
* if( keyboardIsShown )
* return;
*/
userInfo = [n userInfo];
keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
viewFrame = [[self scrollView] frame];
viewFrame.size.height += ( keyboardSize.height - TABBAR_HEIGHT );
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.5];
[[self scrollView] setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = NO;
NSLog(#"HIDE\n");
}
First of all I'd like to thank you all for this useless work in helping me. I'd like to give you some points, so I'll try to rise a "interest point" for each answer, but I need to choose the right one... hard part... :-)
Excuse me again... I really didn't see the if() statement...
If you read the documents for UIWindow it says that the notification object for these notifications is nil. You are passing self.view.window in as the object to the addObserver:selector:name:object: method. Try passing nil instead:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
It's important to note that when the user hides the software keyboard via the hide button, the hide methods aren't called. The show methods are called again, but the keyboard is nearly off screen except for the home row toolbar.
Check, if keyboardDone really gets called (i.e. with NSLog(#"%#", #"keyboard done called");). If its get called, but resignFirstResponder does not help dismissing the keyboard, then try this:
[self.view endEditing:YES];
Please also provide your keyboardWillHide: method.
To set the keyboard up so that it has a "Done" button, do this:
1) Setup your view controller so that it implements the UITextFieldDelegate. For Example:
#import <UIKit/UIKit.h>
#interface TX_ViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, retain) IBOutlet UITextField *textField;
#end
2) In your view controllers implementation file, use the following code to setup the keyboard:
- (void)viewDidLoad
{
[self.textField setDelegate:self];
[self.textField setReturnKeyType:UIReturnKeyDone];
[self.textField addTarget:self action:#selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
3) And if you wish to do something when the DONE button is pressed, simply add the following function to your view controller's implementation file:
- (IBAction)textFieldFinished:(id)sender
{
[sender resignFirstResponder];
}
Also, if you are using Interface builder to create your interfaces, don't forget to setup your IBOutlet reference for the TextField; otherwise, your class won't receive the messages from the XIB.
I set this up in a sample application just to see if it works and it did perform in the way you wish for your application to perform.
Swift $
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
func keyboardWillHide(notification: NSNotification){
print("keyboardWillHide")
}
I have a view with five UITextFields spaced from top to bottom. When you click in a text field the keyboard pops up and covers the bottom two text fields. I have tweaked the code to the point where if you click in one of the bottom two text fields the view will scroll up so that text field is visible.
The problem I am having is when you start in the first text field and tab through the text fields the view does not scroll when you get to the last two text field. I have determined this is because when tabbing between views my method keyboardWillShow never gets called again after we have clicked in the first text Field.
I have tried using the textFieldDidBeginEditing method to determine which text field now has focus and then I wanted to call my keyboardWillShow method again. But that method takes a NSNotification as an argument and through all of my search I have seen that you never really want to create an NSNotification object and instead want to use postNotificationName from NSNotificationCenter to pass a NSNotification object. I have been unable to get this to work properly.
Here's the relevant code I have.
- (void) viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:self.view.window];
[super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[super viewWillDisappear:animated];
}
- (void) keyboardWillShow: (NSNotification *)notif
{
// get our app delegate so we can access currentTextField
ScrollingAppDelegate *appDelegate = (ScrollingAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.notif = notif;
NSDictionary *info = [notif userInfo];
NSValue *aValue = [info objectForKey: UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
float bottomPoint = (appDelegate.currentTextField.frame.origin.y+ appDelegate.currentTextField.frame.size.height+10);
scrollAmount = keyboardSize.height - (self.view.frame.size.height - bottomPoint);
if (scrollAmount > 0)
{
moveViewUp = YES;
[self scrollTheView:YES];
}
else
{
moveViewUp = NO;
}
}
- (void)scrollTheView: (BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect rect = self.view.frame;
if (movedUp)
{
rect.origin.y -= scrollAmount;
}
else
{
rect.origin.y += scrollAmount;
}
self.view.frame = rect;
[UIView commitAnimations];
}
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
// declare app delegate so we can access a varibale in it.
ScrollingAppDelegate *appDelegate = (ScrollingAppDelegate *)[[UIApplication sharedApplication] delegate];
// set the app delegate variable currentTextField to the textField which just got focus so we can access it
// in our other method keyboardWillShow
appDelegate.currentTextField = textField;
// some how call keyboardWillShow here so the view will scroll to the current text field
}
If I am going about this all wrong please let me know. I have been searching the net for answers but the have eluded me so far. Everything I find about scrolling the view only handles one text field and not multiple the way I need it.
Thanks
I didn't bookmark the original post I found this in, but here's a link to the code snipet I've been using for exactly this kind of thing:
https://gist.github.com/295089
In portaint Actionsheet show in tabbar. In landscape - in window. I heed do remove UIActionSheet from tabbar before rotate, for after rotate show in wondow.
Inside – willRotateToInterfaceOrientation:duration dismiss action sheet dont work.
You can use NSNotification for this. Add this notifier in your viewdidload file you willl get notify when orientation is going to change:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(OrientationChanged:)
name:#"UIDeviceOrientationDidChangeNotification"
object:nil];
…add this method:
-(void)OrientationChanged
{
}
See NSNotification class reference.
Me i dismiss before rotation and show after, then the UIActionSheet is replaced at middle;
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[APP.validSave dismissWithClickedButtonIndex:1 animated:NO];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[APP.validSave showInView:APP.navController.view];
}
I have a UIViewController whose view is a UIWebView with an embedded movie. When the movie is playing full screen, and the device is rotated, the title bar ends up behind the status bar after the movie is dismissed. Why might this happen?
Turns out that the animation of the view controller's view wasn't finished when the video started. This caused it to be redisplayed over the video player view.
My solution:
(void)viewDidLoad
{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:NO];
[UIApplication sharedApplication].keyWindow.frame=CGRectMake(0, 20, 320, 460);
self.navigationController.navigationBar.hidden=NO;
}
did you autoresizingMask on the UIWebView
webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth);
and
-(BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) orientation
{
return YES;
}
It's no way to resolve this problem using MPMoviePlayerNotification, because UIWebView Video Don't use MPMoviePlayerViewController or it's private for developer.
But, there's another way to fix this bug.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleStatusBarFrameDidChange)
name:UIApplicationDidChangeStatusBarFrameNotification
object:nil];
- (void)handleStatusBarFrameDidChange {
self.navigationController.navigationBarHidden = YES;
self.navigationController.navigationBarHidden = NO;
}
I need to move UI elements of my view controller when keyboard appears. I do this by registering for the keyboard notifications in my app delegate:
[[NSNotificationCenter defaultCenter] addObserver:observer
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:observer
selector:#selector(keyboardWasHidden:)
name:UIKeyboardDidHideNotification object:nil];
and then handling notification as prescribed by Apple (I have similar code for keyboard was shown) to scroll the view up and down:
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
CGRect viewFrame = [self.view frame];
viewFrame.origin.y += keyboardSize.height - TOOLBAR_HEIGHT;
self.view.frame = viewFrame;
}
So far so good. Now problem description:
When I execute this code to show OS 3.0 specific message UI:
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[self presentModalViewController:picker animated:YES];
and when keyboard shows in the actual mail UI, I still get keyboard notification which scrolls my view and therefore breaking my UI (note that mail controller takes entire screen and my view is not even visible at this point).
I was hoping to temporary disable keyboard notification, so my scrolling code would not get called with this line:
[[NSNotificationCenter defaultCenter] removeObserver:self];
But it does not help, keyboard even still get posted.
What should I do avoid reacting on the keyboard when it created by the message UI?
Add a BOOL property or instance variable: careAboutKeyboard that's accessible to both your keyboardWasShown: and keywardWasHidden: methods, likely in the view controller those methods are in.
Have it set to YES when in the viewWillAppear method, and set to NO when you show the mail view and in viewWillDisappear.
Then put all of your scrolling logic in an if block:
if(careAboutKeyboard) {
// Scrolling logic
}