I have a View embedded inside a Scroll View. I have written code such that when the cursor is placed in a text field (within the View) that is hidden by the keyboard that the screen will readjust such that the text field is no longer hidden. I am using autolayout to do this.
My problem is that when I put the View in the View Controller at the position I want it, there is a lot of additional white space above when I run the simulator. But when the keyboard comes up (and the screen redraws) then I can scroll up and the View Controller no longer has that additional white space.
If I adjust the view so that there isn't any white space (so it appears as on the storyboard) then when the keyboard appears, I cannot scroll to the top of the View.
I assume this has something to do with how the View is centered within the Scroll View but I have tried numerous adjustments on the constraints in the Size Inspector and cannot resolve this. I would really like to fix this in the storyboard (versus through code) if at all possible...
Here is the code:
- (void) keyboardDidShow:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
kbRect = [self.view convertRect:kbRect fromView:nil];
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbRect.size.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
CGRect aRect = self.view.frame;
aRect.size.height -= kbRect.size.height;
if (!CGRectContainsPoint(aRect, self.activeField.frame.origin) ) {
[self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
}
}
- (void) keyboardWillBeHidden:(NSNotification *)notification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
Turns out that I was setting the EdgeInsets value too high... when I changed from
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbRect.size.height, 0.0);
to
UIEdgeInsets contentInsets = UIEdgeInsetsMake(60.0, 0.0, kbRect.size.height, 0.0);
The positioning was improved.
Related
I've been struggling with this keyboard and scrollview issue for quite sometime now. I'm trying to make a chat room similar to What'sApp and iMessage. I have UITabBar as a root view controller. For the chat room view I have a toolbar at the bottom that contains UITextView and UIButton the issue is that when the keyboard is presented it pushes the content view out of the screen and I can't see about 1/5 of the top of the content view. I tried playing with the numbers and still can't get it to work properly. Any help would be greatly appreciated.
- (void)keyboardWasShown:(NSNotification *) aNotification {
NSDictionary *info = [aNotification userInfo];
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// the hardcoded 49 is the height of the UITabBar at the bottom below the input toolbar
UIEdgeInsets contentInsets = UIEdgeInsetsMake((-keyboardSize.height+49), 0.0, (keyboardSize.height-49), 0.0);
self.scrollView.contentInset = contentInsets;
self.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 aaRect = self.view.frame;
// aaRect.size.height -= keyboardSize.height;
// if (!CGRectContainsPoint(aaRect, self.activeTextView.frame.origin)) {
// [self.scrollView scrollRectToVisible:self.activeTextView.frame animated:NO];
// }
CGPoint scrollPoint = CGPointMake(0, self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:scrollPoint animated:true];
[self.view addGestureRecognizer:self.tapRecognizer];
}
- (void)keyboardWillBeHidden:(NSNotification *) aNotification {
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
[self.view removeGestureRecognizer:self.tapRecognizer];
}
I met the same problem long time ago. My solution is to listen keyboard frame did change notification(because different keyboard has different frame). And I think it is easier to adjust the frame of scroll view rather than content offset.
I use the following when show/hide the keyboard:
- (void)keyboardWasShown:(NSNotification *)notification
{
NSDictionary *info = [notification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.scrDetails.contentInset = contentInsets;
self.scrDetails.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
/* Set to NO so after the keyboard is hidden, the size goes back to normal */
self.automaticallyAdjustsScrollViewInsets = NO;
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrDetails.contentInset = contentInsets;
self.scrDetails.scrollIndicatorInsets = contentInsets;
[self.view layoutIfNeeded];
}
But for some reason even though the size is set correctly when dismissing the keyboard
(lldb) po self.scrDetails.contentInset
(top = 0, left = 0, bottom = 0, right = 0)
the effect is not shown on the device/simulator(the scrollbar remain at the previous keyboard up position)
See the image
I use autolayout, so I am not setting the contentSize directly.
Any suggestions what might help tracking this down?
You can use third party class TPKeyboardAvoiding. It manage keyboard.
Link : https://github.com/michaeltyson/TPKeyboardAvoiding
I have textViews in a tableView. When textViews (towards the bottom of the tableView) get selected the keyboard pops up, and hides the textView, and you can't scroll down either. So I added the following code:
- (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);
myTableView.contentInset = contentInsets;
myTableView.scrollIndicatorInsets = contentInsets;
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
[self.myTabelView scrollRectToVisible:activeField.frame animated:YES];
}
}
I now have the opposite problem. When the keyboard does show, towrad the top doesn't show, and it's not possible to scroll all the way up either.
Hi and did you try to use TPKeyboardAvoiding ? I use it to solve such cases without to need to code anything... You can try it as CocoaPod quickly.
I have been pulling my hair out trying to fix this problem the last few weeks. I move up the entire view contained in my view controller when the keyboard appears. Once I do so the top portion of my scrollview contained in the view becomes unreachable. It is like the top of the screen is cutting off the top portion of my scrollview. Is there some way to fix this?
//Move the keyboard when you select a textfield.
-(void)keyboardWillShow:(NSNotification*)notification{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect viewRect = self.view.frame;
viewRect.origin.y = -215;
[UIView animateWithDuration:0.3f animations:^ {
self.view.frame = viewRect;
}];
scrollBounces = YES;
scrollView.contentOffset = CGPointZero;
}
This is all that I am doing to the view that contains the scrollview.
You can set the contentInset and scrollIndicatorInsets for the scrollView too:
[scrollView setContentInset:UIEdgeInsetsMake(215, 0, 0, 0)];
[scrollView setScrollIndicatorInsets:UIEdgeInsetsMake(215, 0, 0, 0)];
Write the below three lines in the keyboardWillShow
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kKeyboardHeightValue, 0.0);
self.mDisplayedScrollview_.contentInset = contentInsets;
self.mDisplayedScrollview_.scrollIndicatorInsets = contentInsets;
Write the below three lines in the keyboardWillHide
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.mDisplayedScrollview_.contentInset = contentInsets;
self.mDisplayedScrollview_.scrollIndicatorInsets = contentInsets;
I read many topics but I cannot find a solution :-( maybe you can help!
In my storyboard (for iPad App) I have the following:
- a Navigation Controller that is my initial Scene
- a Segue that opens a View Controller that contains the following hierarchy:
- Scroll View
-> Toolbar
-> BAR Button Item
-> Search Bar With Prompt
-> Map View
- Navigation Item
-> Bar Button item
My Search Bar is in the bottom toolbar and as a consequence when I click on it the keyboard is displayed and it hides my Search Bar. I would like to scroll up everything to display my Search Bar (Navigation, Map, Toolbar...).
I have registered the Keyboard notifications and implemented the code as described in the IOS documentation
- (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 application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y-kbSize.height);
[scrollView setContentOffset:scrollPoint animated:YES];
}
}
When this code is executed, it seems something happens (My map view display a white view instead of the map) and the keyboard is displayed but my Search bar is still invisible.
Is there a issue in my View hierarchy? because it's embedded in a Navigation controller? I'm a little bit lost for this issue. Just a point, before to have a scrollView in my hierarchy I had a simple View, just replaced the simple view with the scroll view because of the issue with the Search Bar.
Your helps will be very appreciated!
Thanks,
Sébastien.
I found my mistake, it's because my App is in Landscape mode and the uiSearchBar position is relative to the toolbar.
Below is the fix
- (void)keyboardWasShown:(NSNotification *)aNotification {
// Get the Keyboard size
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// Add to the scroll view a bottom inset equal to height of the keyboard
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.width; // in landscape mode need to get width and not height!
// Compute the position of the uiSearchBar in the screen (whole scrollview)
CGPoint realPoint = [_LocateCell convertPoint:_LocateCell.frame.origin toView:self.scrollView];
if (!CGRectContainsPoint(aRect, realPoint) ) {
CGPoint scrollPoint = CGPointMake(0.0, kbSize.width);
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
}