IOS: UITextField+UITableView inside UIScrollView - ios

I am new in iOS. I am making a chat application so I have a UITextField below the UITableView and UITextField and UITableView are inside the UIScrollView (I have disable the scroll in scrollview by self.scrollView.scrollEnabled = NO;).
When I tap on UITextField, the keyboard was shown, so I move the UITextField to above keyboard follow Managing the Keyboard doc
// 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);
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 aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, self.activeField.frame.origin) ) {
[self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
self.activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
self.activeField = nil;
}
With this code, my TextField move to above keyboard successful
But the problem is: In the TableView, when the keyboard was shown I cannot scroll to see some items on top (about 2 items).
For example, if my tableview have 10items, when the keyboard was shown, i can only see 8items, 2 rest items still exist but I cannot scroll to them
Here is my Demo Project
I think maybe the content inset of UITableView is wrong but I don't know how to fix it.
Any help would be great appreciated

Use Autolayout insteads of contentInsets
In ViewController.h
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *botConstraint;
In ViewController.m
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.botConstraint.constant = kbSize.height;
[self.view layoutIfNeeded];
//...
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
self.botConstraint.constant = 0.0f;
[self.view layoutIfNeeded];
//...
}
botConstraint is UITextField/UITableView/UIScrollView .bottom = fatherView.bottom in your Main.storyboard

Related

Keyboard pushes UIScrollView content out of screen

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.

UIScrollView contentInset reset not working iOS8/9

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

UITextfield : Text jumps up and down while typing

I am having problem with the textfield input. In the 'CommentviewController' I have a scrollable tableview to display the previous comments, and at the bottom is a UItextField for the user to enter the comment and post it. The problem is: when I tried to type in the textfield and the keyboard is toggled, the text jumps up and down while I 'm typing. For example, the first char I typed is above the keyboard, and the second is below and behind the keyboard. Anybody has any idea about the cause? The test device is a 64 GB itouch5, and the code is written in objective C, and I am using the Xcode 6.3.2.
<i>`- (void)keyboardWasShown:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
theKBSize = kbSize;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height - 10, 0.0);
self.tvComment.contentInset = contentInsets; self.tvComment.scrollIndicatorInsets = contentInsets;
CGRect uvFrame = _uvComment.frame;
uvFrame.origin.y = self.view.frame.size.height - kbSize.height - _uvComment.frame.size.height; _uvComment.frame = uvFrame; } `</i>
<i> `- (void)keyboardWillBeHidden:(NSNotification*)aNotification {
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
_tvComment.contentInset = contentInsets;
_tvComment.scrollIndicatorInsets = contentInsets;
}`</i>
<i>`- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if(string==nil || [string length]<1) {
[self.btnSend setEnabled: NO];
}else {
[self.btnSend setEnabled: YES];
}
return YES;
}`</i>
Are you changing the scroll position of the tableView?
A UITableView will automatically scroll so that the UITextField is not hidden by the keyboard when selected and the keyboard pops up. If you are changing the scroll position, that could be interfering with the auto scroll behavior.

Why does the UITableVIew scroll down but not up when keyboard is shown?

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.

Static Table View - UITextField hidden by Keyboard

Maybe this is a recurrent question, but I got stuck with this issue and some iOS concepts. I have a ViewController with a Static Table View, Three Sections and some Rows on Each Section. Inside the rows I have UITextFields. What I’m trying to do is preventing the keyboard to hide my bottom screen UI Text Fields. I’ve just tried an apple solution from Managing the Keyboard, but since I'm not getting the concept behind the scroll view attached to a static table view, I couldn't implement the idea into my project. Do you guys recommend anyplace to learn it? Sorry if couldn't explain what I'm trying to do. I'm a little lost.
Any help will be appreciated.
Many thanks,
Marcos.
I've had to do something similar, here's my code, hopefully it helps you.
- (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;
CGRect aRect = self.bounds;
aRect.size.height -= kbSize.height;
CGRect activeRect = [activeTextField convertRect:activeTextField.frame toView:self];
if (!CGRectContainsPoint(aRect, activeRect.origin) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeRect.origin.y-kbSize.height+10);
[scrollView setContentOffset:scrollPoint 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
{
self.activeTextField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
self.activeTextField = nil;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
Also, make sure to set your notification observers when loading your view, like this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
Just define activeTextField as a UITextField and make sure everything you want to move is contained in your scrollView (in your case you can probably change your viewController to a scrollView). Also, make sure your scrollView's contentSize is at least self.bounds.size.
Hope this helps.
I just had to do this in my application - Stakenborg's answer got me 80% there, but there were a couple of additional refinements I added to work with TableViews specifically.
The main bits are that:
TableViews already have insets, so we need to add or subtract from those.
I also want to scroll so that the cell I'm editing is in a good place to be seen.
The second part requires a little bit of indirection - the text fields belong to my custom cells, so I need to respond to the BeginEditing message there by sending a message to the UITableViewController.
Here's how it all comes together. In the UITableViewController:
#property (nonatomic, strong) NSIndexPath *editCellIndexPath;
#property (nonatomic) bool keyboardShowing;
//....
- (void)setEditRow:(UITableViewCell *)cell
{
self.editCellIndexPath = [self.tableView indexPathForCell:cell];
if (self.keyboardShowing)
{
[self.tableView scrollToRowAtIndexPath:self.editCellIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:true];
}
}
- (void)keyboardWillShow:(NSNotification *)sender
{
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIEdgeInsets edgeInsets = [self.tableView contentInset];
edgeInsets.bottom += kbSize.height;
UIEdgeInsets scrollInsets = [self.tableView scrollIndicatorInsets];
scrollInsets.bottom += kbSize.height;
self.keyboardShowing = true;
[UIView animateWithDuration:duration animations:^{
[self.tableView setContentInset:edgeInsets];
[self.tableView setScrollIndicatorInsets:scrollInsets];
}];
}
- (void)keyboardWillHide:(NSNotification *)sender
{
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIEdgeInsets edgeInsets = [self.tableView contentInset];
edgeInsets.bottom -= kbSize.height;
UIEdgeInsets scrollInsets = [self.tableView scrollIndicatorInsets];
scrollInsets.bottom -= kbSize.height;
self.keyboardShowing = false;
[UIView animateWithDuration:duration animations:^{
[self.tableView setContentInset:edgeInsets];
[self.tableView setScrollIndicatorInsets:scrollInsets];
}];
}
Then I have a weak property for the owningController in each of my custom UITableViewCells, and let the controller know when my cell is being text-edited. I use a TextView in one, and TextFields in another row, so I use these methods:
- (void)textViewDidBeginEditing:(UITextView *)textView
{
MyCustomTableController *itemControl = (MyCustomTableController *)self.owningController;
[itemControl setEditRow:self];
}
and
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
MyCustomTableController *itemControl = (MyCustomTableController *)self.owningController;
[itemControl setEditRow:self];
}
So far, this is working very well.

Resources