UITextView not resizing along woth keyboard showing - iphone

I have a text view (nib-file) with a UITextView maximised the entire view.
When ever i push the viewcontroller on to the navigationcontroller i load the keyboard in the text view's viewDidLoad method.
My problem is that when i write text that has more lines than there is space for, the text is behind the keyboard. I followed the sampe from Apple here.
If i log the "newTextViewFrame" it's NULL. but if i debug the thing it has a fine value.
Even if i hardcode it, the UITextView doesent change size.
Here is my code:
- (void)keyboardWillShow:(NSNotification *)notification {
/*
Reduce the size of the text view so that it's not obscured by the keyboard.
Animate the resize so that it's in sync with the appearance of the keyboard.
*/
NSDictionary *userInfo = [notification userInfo];
// Get the origin of the keyboard when it's displayed.
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
// Get the top of the keyboard as the y coordinate of its origin in self's view's coordinate system. The bottom of the text view's frame should align with the top of the keyboard's final position.
CGRect keyboardRect = [aValue CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
CGFloat keyboardTop = keyboardRect.origin.y;
CGRect newTextViewFrame = self.view.bounds;
newTextViewFrame.size.height = keyboardTop; - (self.view.bounds.origin.y);
// Get the duration of the animation.
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
// Animate the resize of the text view's frame in sync with the keyboard's appearance.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
createListingTextView.frame = newTextViewFrame;
[UIView commitAnimations];
NSLog(#"Textview resized: %#", newTextViewFrame);
}
My task i simple: Implement a View with a UITextView and the keyboard open and scroll the UITextView when ever the text exceeds.
Please advice...

There is a semi-colon after keyboardTop on the line
newTextViewFrame.size.height = keyboardTop; - (self.view.bounds.origin.y);
This would certainly prevent newTextViewFrame from getting the adjusted height.

Related

Using NSLayoutConstraint on UITextView resets contentSize to {0,0}

I have a UITextView on which I am using an NSLayoutConstraint to dodge the keyboard. Here's the constraint:
self.textViewBottomConstraint = [NSLayoutConstraint constraintWithItem:textView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
[self.view addConstraint:self.textViewBottomConstraint];
When the keyboard shows/hides I animate the constraint by setting the constraint constant to the keyboard height. However, doing so for some reason resets the contentSize to {0,0}, thus breaking scrolling. I've added a hack to handleKeyboardDidHide: to reset the contentSize to what it was before being reset, but this has some ugly side effects such as the scroll position being reset and the view not scrolling to the cursor position until typing starts.
- (void) handleKeyboardDidShow:(NSNotification *)notification
{
CGFloat height = [KeyboardObserver sharedInstance].keyboardFrame.size.height;
self.textView.constant = -height;
[self.view layoutIfNeeded];
}
- (void) handleKeyboardDidHide:(NSNotification *)notification
{
// for some reason, setting the bottom constraint resets the contentSize to {0,0}...
// so let's save it before and reset it after.
// HACK
CGSize size = self.textView.contentSize;
self.textView.constant = 0.0;
[self.view layoutIfNeeded];
self.textView.contentSize = size;
}
Anyone know how to avoid this issue altogether?
I don't know what's wrong with your code, and we can deal with that in detail if you want. But as an initial suggestion, if possible, don't resize the UITextView: just change its content and scroll insets, like this:
- (void) keyboardShow: (NSNotification*) n {
NSDictionary* d = [n userInfo];
CGRect r = [d[UIKeyboardFrameEndUserInfoKey] CGRectValue];
self.tv.contentInset = UIEdgeInsetsMake(0,0,r.size.height,0);
self.tv.scrollIndicatorInsets = UIEdgeInsetsMake(0,0,r.size.height,0);
}
Even so, I find that you have to wait until the keyboard hide animation completes before resetting those values:
- (void) keyboardHide: (NSNotification*) n {
NSDictionary* d = [n userInfo];
NSNumber* curve = d[UIKeyboardAnimationCurveUserInfoKey];
NSNumber* duration = d[UIKeyboardAnimationDurationUserInfoKey];
[UIView animateWithDuration:duration.floatValue delay:0
options:curve.integerValue << 16
animations:
^{
[self.tv setContentOffset:CGPointZero];
} completion:^(BOOL finished) {
self.tv.contentInset = UIEdgeInsetsZero;
self.tv.scrollIndicatorInsets = UIEdgeInsetsZero;
}];
}
(It may be that that trick would help your code somehow as well.)

NSNotificationCenter

Right now I'm trying to write a function to moving up frame when keyboard appears on the screen.
I started to use NSNNotificationCenter. My code is working but not correctly. When keyboard appears my formView is moving up but when I start to edit next textField in formView, formView is moving up again. What's wrong with my code?
Thanks.
- (void)keyboardWillShow:(NSNotification *) aNotification {
NSDictionary *userInfo = [aNotification userInfo];
CGRect frame = self.formView.frame;
frame.origin.y -= 170;
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
formView.frame = frame;
[UIView commitAnimations];
}
You should add again your 170 pixels (or whatever you calculate as suggested by Mike) to the origin.y of your view when the keyboard is disappearing. When you click on another text field, technically the current keyboard will disappear (your view does not react in any way) and a new keyboard will appear (your keyboardWillShow will be called again and you shift your view again up by 170 px).

UITextView Not Scrolling after updating its frame

I have registered for notifications of Keyboard showing and Hiding.
The text View is scrollable when not clicked on it.. i.e. when it is not in editable mode..
When user click .. i update its frame to come up ..and after that it doesn't scroll.. after ending editing.. i change its position back its scrollable again..
Here is my code
- (void)keyboardWillHide:(NSNotification *)n
{
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect viewFrame = self.NoteTextView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.origin.y += (keyboardSize.height * 0.36);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
// The kKeyboardAnimationDuration I am using is 0.3
[UIView setAnimationDuration:0.1];
[UIView commitAnimations];
[self.NoteTextView setContentSize:CGSizeMake(310,580)];
[self.NoteTextView setScrollEnabled:YES];
keyboardIsShown = NO;
}
- (void)keyboardWillShow:(NSNotification *)n
{
// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the UIScrollView if the keyboard is already shown. This can happen if the user, after fixing editing a UITextField, scrolls the resized UIScrollView to another UITextField and attempts to edit the next UITextField. If we were to resize the UIScrollView again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown.
if (keyboardIsShown) {
return;
}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.NoteTextView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.origin.y -= (keyboardSize.height * 0.36);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
// The kKeyboardAnimationDuration I am using is 0.3
[UIView setAnimationDuration:0.3];
[self.NoteTextView setFrame:viewFrame];
[UIView commitAnimations];
[self.NoteTextView setContentSize:CGSizeMake(310, 580)];
[self.NoteTextView setScrollEnabled:YES];
keyboardIsShown = YES;
}
I have even enabled scrolling enabled and changed its content size in the methods.
It sound really weird.
My Suggestions:
1. Check that non of its superview's UserInteractioEnable property in the new frame isn't false
2. Try this code on new and clear project.

IPhone Keyboard hides UISeachBar

I have a search bar at the bottom of a view. The issue is whenever I type something in the keyboard, the search bar still remains at the bottom and I cannot view what I am typing. I would like to dynamically move it up whenever the keyboards pops up and then take back its original position after the keyboard disappears. And unfortunately the search bar has to be in the bottom for my app and kind of stuck in this.
Is there any way around to move the search bar up only when the keyboard appears? Any code snippets would be really helpful.
Your best bet is probably to use the –searchBarShouldBeginEditing: in the UISearchBarDelegate protocol.
It would look something like this :
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
CGRect newFrame = //some rect
mySearchBar.frame = newFrame;
return YES;//this is important!
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
CGRect originalFrame = //the original frame
mySearchBar.frame = originalFrame;
return YES;
}
EDIT: One of the other answers suggests using the UIKeyboard notifications, but that can be confusing. It does, however, give the advantage of working for every time the keyboard appears, rather than just when the UISearchBar is the first responder.
EDIT 2:
Mayur Joshi suggests using animation, which can be done like so:
[UIView animateWithDuration:duration
animations:^{
//what you want to animate (in this case, the search bar's frame)
}
completion:^(BOOL finished){
//what to do when the animation finishes
}];
EDIT 3:
If you don't want to obscure the view behind the search bar, you will have to shrink its height whenever the search bar moves up. It can go in the same place as the code to animate your search bar.
Hi, try this
sBar is UISearchBar object.
- (void)keyboardWillShow:(NSNotification *)aNotification
{
// the keyboard is showing so resize the table's height
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = sBar.frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
frame.origin.y=frame.origin.y- keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
sBar.frame = frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
// the keyboard is hiding reset the table's height
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = sBar.frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
frame.origin.y=frame.origin.y+ keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
sBar.frame = frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
[UIView commitAnimations];
}
You will have to use a UIScrollView and keep this search bar in that scroll View. Now, when you start editing the Search Bar, that is,
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar
set the scrollRectToVisible method for the UIScrollView so as to make your SearchBar visible like this....
[yourScrollView scrollRectToVisible:CGRectMake(0, 300, yourScrollView.frame.size.width, yourScrollView.frame.size.height) animated:YES];
And when you have written the text in the search bar, i.e
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar1
set the Scroll view scrollRectToVisible to its original size.
[yourScrollView scrollRectToVisible:CGRectMake(0, 0, yourScrollView.frame.size.width, yourScrollView.frame.size.height) animated:YES];

How to measure position of UI objects on iPhone simulator screen

I have calculated positions and offsets on paper. I have written code and debugged that I get expected results. However on iPhone Simulator things are overlapping by about 15 pixels.
To go on with my debugging, I need to know where exactly UI objects are on the screen.
Related to popup search keyboard and resizing a UITableView between static UISearchBar and dynamically added UITabBar (table view is embedded into one of the tabs). No, I really don't want to use any hardcoded values due rotation and different screen sizes.
How can I find out this?
- (void)keyboardWasShown:(NSNotification*)aNotification
{
if (self.keyboardShown)
return;
// Get keyboard dimensions
NSDictionary* info = [aNotification userInfo];
NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize kbSize = [aValue CGRectValue].size;
NSValue* endValue = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
CGPoint endCenter = [endValue CGPointValue];
CGRect frame = myView.frame;
frame.size.height = endCenter.y - kbSize.height/2 - frame.origin.y;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
myView.frame = frame;
[UIView commitAnimations];
self.keyboardShown = YES;
}
...code just in case there're obvious bugs I can't see anymore...
Your best bet is probably UIView's convertPoint:toView:. To find out where a given view is located, use:
CGPoint myPoint = [myView convertPoint:CGPointMake(0, 0) toView:((YourAppDelegate *)[[UIApplication sharedApplication] delegate]).window];