iPhone SDK: TextView, Keyboard in Landscape mode - iphone-sdk-3.0

How do I make sure that the textview is shown and the keyboard is not obscuring the textview, while in landscape.
Using UICatalog I created a TextViewController which works. In it there are two methods for calling the keyboard and making sure that textView is positioned above the keyboard. his just works great in Portrait mode.
I got the Landscape mode working, but on the textView is still being put to the top of the iPhone to compensate for the keyboard in portrait mode.
I changed the methods for showing the keyboards.
Below is the code for this methods: (I will just let see the code for show, since the hide code will be the reverse..
- (void)keyboardWillShow:(NSNotification *)aNotification
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait) {
// the keyboard is showing so resize the table's height
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.size.height -= keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
NSLog(#"Left"); // Verijderen later
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.size.width -= keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
} else if (orientation == UIInterfaceOrientationLandscapeRight){
NSLog(#"Right"); // verwijderen later.
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.size.width -= keyboardRect.size.width;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
}
}
I know that I have to change the line frame.size.height -= keyboardRect.size.height but I do not seem to get it working.
I tried frame.size.width -= keyboardRect.size.height that did not work. Losing the keyboardRect and frame all together work, however off course the keyboard obscures the textview........

I found the above code wouldn't work when in Landscape Mode on iPad
Note: I am moving all Fields, as in my case that's what i needed :-)
- (void)keyboardWillShow:(NSNotification*)aNotification {
// Only do for Landscape Mode
if (UIInterfaceOrientationIsLandscape([self interfaceOrientation])){
NSDictionary *info = [aNotification userInfo];
NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.x -= keyboardSize.height-44;
frame.origin.y -= keyboardSize.height-44;
frame.size.height += keyboardSize.height-44;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
viewMoved = YES;
}
keyboardInUse = YES;
}
- (void)keyboardWillHide:(NSNotification*)aNotification {
if (UIInterfaceOrientationIsLandscape([self interfaceOrientation])){
if (viewMoved) {
NSDictionary *info = [aNotification userInfo];
NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.y += keyboardSize.height-44;
frame.origin.x += keyboardSize.height-44;
frame.size.height -= keyboardSize.height-44;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
viewMoved = NO;
}
}
keyboardInUse = NO;
}

If you think you need different code for the different orientations, you're doing something else wrong. Once the orientation has changed and your superview has responded, the value that needs changing should always be the frame's height.

Here is a code that I use for this purpose. It works on both iPad and iPhone is landscape and portrait modes (inspired by a code from Apple documentation):
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float offset;
if UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
offset = kbSize.height;
else
offset = kbSize.width;
[UIView animateWithDuration:0.5
animations:^{
CGRect frameTxtField = myTextField.frame;
frameTxtField.origin.y -= offset;
myTextField.frame = frameTxtField;
}
];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float offset;
if UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
offset = kbSize.height;
else
offset = kbSize.width;
[UIView animateWithDuration:0.5
animations:^{
CGRect frameTxtField = myTextField.frame;
frameTxtField.origin.y += offset;
myTextField.frame = frameTxtField;
}
];
}
Don't forget to call the registerForKeyboardNotifications method (e.g., in viewDidLoad).

Related

UIView.animateWithDuration not animating when called inside keyboardWillShow

For some reason my view is not animating:
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
double duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
int curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
int height = self.view.bounds.size.height - kbSize.height+self.tabBarController.tabBar.frame.size.height;
self.notesView.frame = CGRectMake(0, -height,
self.view.bounds.size.width, height);
[UIView animateWithDuration:1.5 delay:0 options:curve animations:^{
self.notesView.frame = CGRectMake(0, 0, self.view.bounds.size.width, height);
} completion:nil];
}
The notesView is being displayed but not animated. When I move the animation code into a btnPressed method then it animates as expected. Any ideas?
Edit
It looks like the method is being called twice (that's a separate problem dealing with the inputAccessoryView that I still need to figure out). I updated it to see if calling the animateWithDuration code only once would solve the problem. However, it's still not animating.
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
int curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
int height = self.view.bounds.size.height - kbSize.height + self.tabBarController.tabBar.frame.size.height;
if (height == 510) return; //for some reason the self.view.bounds.size.height is different between the two calls
self.notesView.frame = CGRectMake(0, -height, self.view.bounds.size.width, height);
[UIView animateWithDuration:1.5 delay:0 options:curve animations:^{
self.notesView.frame = CGRectMake(0, 0, self.view.bounds.size.width, height);
} completion:nil];
}

UIScrollView does not move view ontop of keyboard iPad

I have several text fields on screen. When I tap inside of the one towards the bottom, the keyboard appears over them.
I've referred to apple's documentation and used the following code to try and tackle this.
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
activeField = nil;
}
What i'd like to happen, when the keyboard appears the text fields that in side the scroll field will move up. Any help is appreciated.
Use This Code for Move the view up..........
-(void) textFieldDidBeginEditing:(UITextField*)textField
{
[self slideViewUpForTextField:textField];
}
-(void) slideViewUpForTextField:(UITextField *)textField
{
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.origin.y + 3.0 * textFieldRect.size.height;
CGFloat numerator = midline - viewRect.origin.y - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator = (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION) * viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
heightFraction = 0.0;
else if (heightFraction > 1.0)
heightFraction = 1.0;
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
else
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
And write these on top of the class
And After #import"".....
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 158;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;
This is also write ....
-(void) textFieldDidEndEditing:(UITextField*) textField
{
CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}

Setting UIView Frame

I'm trying to resize my UITextView when the keyboard appears, but I don't know what I'm doing wrong.
I have these three lines of code called when the keyboard appears:
CGSize kbSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
textView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height-kbSize.height);
NSLog(#"%f,%f,%f,%f", textView.frame.origin.x, textView.frame.origin.y, textView.frame.size.width, textView.frame.size.height);
For some really odd reason my keyboard doesn't appear and here is what is logged:
0.000000,-180.000000,480.000000,180.000000
Why is the CGRects y origin getting set to -180 when it is hardcoded in at 0?
EDIT: textView is a UITextView I created programatically. I didn't use Interface Builder.
EDIT2: It seems that the problem is that the view is autoresizing when rotated.
You can try this :
- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
keyboardFrame.size.height -= tabBarController.tabBar.frame.size.height;
newFrame.size.height -= keyboardFrame.size.height * (up?1:-1);
textView.frame = newFrame;
[UIView commitAnimations];
}
Hope it'll help

How to move view for keyboard in portrait orientations

I have an app that runs in portrait and portraitUpsideDown only. I need to push the view up when the keyboard appears and pull it back down when it disappears. The following code works perfectly if the device stays in portrait, but if it is in portraitUpsideDown the view moves the wrong direction (-260 instead of 260), plus if the orientation changes while the keyboard is showing, it's not handled... The keyboardWillHide method works fine in both orientations. Is there a way to move the view RELATIVE to the keyboard or status bar so it doesn't matter what orientation the device is in???
- (void) keyboardWillShow:(NSNotification *) notification
{
NSLog(#"Keyboard Will Show");
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y + -260);
}completion:^(BOOL finished){
}];
}
- (void) keyboardWillHide:(NSNotification *) notification
{
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
NSLog(#"Keyboard Will Hide");
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
[self.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}completion:^(BOOL finished){
}];
}
I solved it (less than elegantly) this way:
NOTE: Things you SHOULD do, and I will change this code to do them eventually are: create a property to hold the keyboard animation duration so I can use it outside of the keyboard delegate methods, and similarly create a property for the offset and determine it using the userInfo for the height of the keyboard.
- (void) keyboardWillShow:(NSNotification *) notification
{
NSLog(#"Keyboard Will Show");
if (self.interfaceOrientation == UIInterfaceOrientationPortrait)
offset = -260;
else
offset = 260;
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y + offset);
}completion:^(BOOL finished){
}];
}
- (void) keyboardWillHide:(NSNotification *) notification
{
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
NSLog(#"Keyboard Will Hide");
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y - offset);
}completion:^(BOOL finished){
}];
}
- (void) keyboardDidShow
{
NSLog(#"Keyboard Did Show");
keyboardIsShowing = YES;
}
- (void) keyboardDidHide
{
NSLog(#"Keyboard Did Hide");
keyboardIsShowing = NO;
}
-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (keyboardIsShowing && UIInterfaceOrientationIsPortrait(toInterfaceOrientation))
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait && offset == 260)
offset = -260;
else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown && offset == -260)
offset = 260;
else
return;
[UIView animateWithDuration:.25 delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y + 2* offset);
}completion:^(BOOL finished){
}];
}
}
Unfortunately you will have to manage this yourself. You can interrogate the current orientation and set your y-axis adjustment appropriately.
int movementDistance = -260;
if (UIInterfaceOrientationPortraitUpsideDown == [self interfaceOrientation]) movementDistance = -movementDistance;
You need to set the frame height, or set the contentInset for the view, not the center.

Animate UIButton becoming hidden and unhidden

So, I have a UIButton that, when a UITextField is in editing mode, becomes hidden and unhidden. The problem is, it changes perfectly fine (from hidden to unhidden), but doesn't animate. I've tried setAlpha: instead, but that only works when it is setting its alpha from 0 to 100, not 100 to 0. Here is my code so far:
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField
{
negButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
negButton.frame = CGRectMake(textField.frame.origin.x, textField.frame.origin.y, 37, textField.frame.size.height);
[negButton setHidden:YES];
return YES;
}
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
if ([textField isEditing])
{
[UIView animateWithDuration:0.3 animations:^
{
CGRect frame = textField.frame;
frame.size.width -= 40;
frame.origin.x += 40;
[negButton setHidden:NO];
[textField setFrame:frame];
[self.view addSubview:negButton];
}];
}
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
[UIView animateWithDuration:0.3 animations:^
{
CGRect frame = textField.frame;
frame.size.width += 40;
frame.origin.x -= 40;
[negButton setHidden:YES];
[negButton removeFromSuperview];
[textField setFrame:frame];
}
];
}
EDIT: I resolved the issue. I just didn't have to call the removeFromSuperview function, and I had to switch from hidden to alpha. (See #David's answer below)
You have a problem with your animations. Change it to the following:
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField
{
negButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
negButton.frame = CGRectMake(textField.frame.origin.x, textField.frame.origin.y, 37, textField.frame.size.height);
[negButton setAlpha:0];
[self.view addSubView:negButton];
return YES;
}
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
if ([textField isEditing])
{
CGRect frame = textField.frame;
frame.size.width -= 40;
frame.origin.x += 40;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
[negButton setAlpha:1];
[textField setFrame:frame];
[UIView commitAnimations];
}
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
CGRect frame = textField.frame;
frame.size.width += 40;
frame.origin.x -= 40;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
[negButton setAlpha:0];
[textField setFrame:frame];
[UIView commitAnimations];
[self performSelector:#selector(removeBtn) withObject:negButton afterDelay:0.3];
}
- (void)removeBtn:(UIButton*)button
{
[button removeFromSuperView];
}
You were removing the button from the view immediately instead of removing it after it had faded out.
Cheers!