nightfixed
nightfixed

Reputation: 841

iOS UITableView contentOffset when keyboard is shown

I am trying to set the contentOffset of a tableView when the keyboard is presented. The actual code is inside a CustomTableView : UITableView <UIScrollViewDelegate>, as it is used widely throughout the app, hence the use of self as the tableView. My code looks like this:

- (void)keyboadDidAppear:(NSNotification *)notification {
    NSTimeInterval animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    CGRect keyboardBeginFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGFloat keyboardHeight = CGRectGetHeight(keyboardBeginFrame);
    CGPoint contentOffset = self.contentOffset;
    originalContentOffset = self.contentOffset;//hold reference to reset it when keyboard is hidden
    contentOffset.y += keyboardHeight;
    [UIView animateWithDuration:animationDuration animations:^{
        [self layoutIfNeeded];
    } completion:^(BOOL finished) {
        if (finished) {
            [self setContentOffset:contentOffset animated:YES];
        }
    }];
}

The problem is that, it always offsets the content by the keyboard's height, which is wrong, when the user taps a tableCell that is near the top of the tableView. Ideally, I would want to offset the content so the tapped tableCell is just above the keyboard. The problem is that I don't know how to do it. I have a rough idea that I would need something like:

distanceBetweenTappedCellAndTableBottom > keyboardHeight ? do nothing : offsetContentBy keyboardHeight + tappedCellHeight.

Any suggestions on how could I come up with the numbers? or is there a better solution?

Later edit:

I can't use the contentInset as the tableView has sectionHeaders, and setting the contentInset causes the sectionHeaders to stay fixes, while the rows move up.

Solution based on suggestions below:

CGSize kbSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

    height += 10.0;//it needs to be slightly higher so the textField is clearly visible.
    originalEdgeInset = self.contentInset;
    __weak typeof (self) block = self;
    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = block.contentInset;
        edgeInsets.bottom += height;
        block.contentInset = edgeInsets;
        edgeInsets = block.scrollIndicatorInsets;
        edgeInsets.bottom += height;
        block.scrollIndicatorInsets = edgeInsets;
    }];

Upvotes: 2

Views: 1172

Answers (1)

Misha
Misha

Reputation: 685

I think keyboard will not move when you add keyboard height into edgeInset as well

  CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

[UIView animateWithDuration:duration animations:^{
    UIEdgeInsets edgeInsets = _generalTableView.contentInset;
    edgeInsets.bottom += height;
    _generalTableView.contentInset = edgeInsets;
    edgeInsets = _generalTableView.scrollIndicatorInsets;
    edgeInsets.bottom += height;
    _generalTableView.scrollIndicatorInsets = edgeInsets;
}];

Upvotes: 3

Related Questions