Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set UITableView contentOffset, then drag, view offset jumps to new position

I have a UITableView that is slightly larger than self.view. I have a UITextField at the bottom of the view, and I use the delegate method – textFieldDidBeginEditing: to move the view up when the text field starts editing.

This works fine, but if I attempt to scroll the view while the UITextField is being edited (and the content is already offset) then the content jerks to the bottom 'appropriate' position for the view. Put another way, the contentOffset.y I set is changed to be equal to the size of the content view (as you would expect for normal behaviour).

Any ideas how to over-ride this behaviour while editing?

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    // Scroll to the currently editing text field
    [self scrollViewToTextField:textField];

}

- (void)scrollViewToTextField:(id)textField
{
    // Set the current _scrollOffset, so we can return the user after editing
    _scrollOffsetY = self.tableView.contentOffset.y;

    // Get a pointer to the text field's cell
    UITableViewCell *theTextFieldCell = (UITableViewCell *)[textField superview];

    // Get the text fields location
    CGPoint point = [theTextFieldCell convertPoint:theTextFieldCell.frame.origin toView:self.tableView];

    // Scroll to cell
    [self.tableView setContentOffset:CGPointMake(0, point.y - 12) animated: YES];
}
like image 334
squarefrog Avatar asked Oct 31 '12 12:10

squarefrog


2 Answers

The way to avoid this behaviour is to apply contentInset at the same time. So for the above example:

- (void)scrollViewToTextField:(id)textField
{
    // Set the current _scrollOffset, so we can return the user after editing
    _scrollOffsetY = self.tableView.contentOffset.y;

    // Get a pointer to the text field's cell
    UITableViewCell *theTextFieldCell = (UITableViewCell *)[textField superview];

    // Get the text fields location
    CGPoint point = [theTextFieldCell convertPoint:theTextFieldCell.frame.origin toView:self.tableView];

    // Scroll to cell
    [self.tableView setContentOffset:CGPointMake(0, point.y - 12) animated: YES];

    // Add some padding at the bottom to 'trick' the scrollView.
    [self.tableView setContentInset:UIEdgeInsetsMake(0, 0, point.y - 60, 0)];
}

Then be sure to reset the inset after editing:

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [self.tableView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
}

The caveat of this approach is that you'll have to implement some checking in the - (void)scrollViewDidScroll:(UIScrollView *)scrollView method to check that your text field is still in view.

The alternative to this is to disable scrolling when editing begins, and reenable scrolling as it ends. You'll have to decide whether this action is bad for UX in your application.

like image 68
squarefrog Avatar answered Oct 31 '22 00:10

squarefrog


I would like to add that if you are using input textfields. And need to scroll then apply a firstResponder that applying an EdgeInset using:

[self.tableView setContentOffset:CGPointMake(0.0f, 0.0f) animated:YES];
[self.tableView setContentInset:UIEdgeInsetsZero];

After stops the auto scroll that happens with input fields within UITableView when they get focus. Thanks @squarefrog

like image 34
elliotrock Avatar answered Oct 31 '22 02:10

elliotrock