Resize and move UITableViewCell smoothly without dismissing keyboard

后端 未结 2 1769
情歌与酒
情歌与酒 2021-01-07 07:05

I have got a UITextView inside a UITableViewCell. As the user edits the UITextView text, I resize the UITextView and I need to resize the UITableViewCell and also make sure

相关标签:
2条回答
  • 2021-01-07 07:18

    hook you constraints properly in cell from top to bottom also don't implement heightForRowAtIndexpath

    then

    in viewDidLoad

    tableView.estimatedRowHeight = 200;
    
    tableView.rowHeight = UITableViewAutomaticDimension;
    

    in data source

      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
           let cell = tableView.dequeueReusableCell(withIdentifier:CellIdentifier1) as! logTableViewCell
    
           // your code here
    
    
        cell.layoutSubviews()
    
        cell.layoutIfNeeded()
    
        return cell
    
    }
    
    0 讨论(0)
  • 2021-01-07 07:35

    I managed to find out how to do it! There are 3 very important details:

    1. The way cells are resized without closing the keyboard. (A normal reload will hide the keyboard).
    2. Setting the cells height only be done after the content offset animation completes. (Otherwise the setContentOffset may be ignored).
    3. Set a bottom inset for the tableView. (Otherwise adjusting the cells size may scroll down the table, hiding the cell we want visible above the keyboard.)

    This solution has been tested in iOS10 and iOS11 with real iPhones.

    Here is how (all code is implemented in the viewController):

    - (TableViewScrollDirection) scrollToKeepEditingCellVisibleAboveVerticalPoint:(CGFloat)verticalPoint cellIndexPath:(NSIndexPath*)cellIndexPath anchorsToVerticalPoint:(BOOL)anchorsToVerticalPoint cellHeight:(CGFloat)cellHeight adjustsCellSize:(BOOL)adjustsCellSize {
    // Remark: verticalPoint is the desired offset above the tableView bottom. In my case the height of the keyboard covering the bottom of the tableView
    
    CGRect cellFrame = CGRectOffset([self.tableView rectForRowAtIndexPath:cellIndexPath], -self.tableView.contentOffset.x, -self.tableView.contentOffset.y - self.tableView.contentInset.top);
    CGFloat cellBottom = adjustsCellSize ? cellFrame.origin.y + cellHeight : cellFrame.origin.y + cellFrame.size.height;
    CGFloat offsetNeeded = cellBottom - verticalPoint; // Relative offset
    CGFloat brandNewOffset = self.tableView.contentOffset.y + offsetNeeded; // Absolute offset
    
    if ((offsetNeeded > 0) || ((offsetNeeded < 0) && anchorsToVerticalPoint))
    {
        CGFloat elasticity = self.tableView.frame.size.height - verticalPoint;
        if (self.tableView.contentInset.bottom != elasticity)
            self.tableView.contentInset = UIEdgeInsetsMake(0, 0, elasticity, 0); // This will make sure the tableview does not scroll down when its content offset elasticity is not enough
    
        if (adjustsCellSize)
            [self setContentOffsetAndAdjustCellSizes:brandNewOffset];
        else
            [self.tableView setContentOffset:CGPointMake(0, brandNewOffset) animated:YES];
    
        if (offsetNeeded > 0)
            return TableViewScrollUp;
        else if (offsetNeeded < 0)
            return TableViewScrollDown;
    }
    
    return TableViewScrollNone;}
    

    The second part of the trick lays on adjusting the cell size only after the scroll animation ends:

    - (void) setContentOffsetAndAdjustCellSizes:(CGFloat)contentOffset{
    [UIView animateWithDuration:0.5 animations:^
    {
        [self.tableView setContentOffset:CGPointMake(0, contentOffset) animated:NO];
    }
    completion:^(BOOL finished)
    {
        [self.tableView beginUpdates]; // Cell height must be adjusted this way, otherwise the keyboard closes.
        [self.tableView endUpdates];
    }];}
    

    Very important: After the keyboard closes, smoothly readjust the tableview scroll (if necessary):

    - (void) keyboardDidHide:(NSNotification *)notification {
    
    if (self.tableView.contentInset.bottom != 0)
        [UIView animateWithDuration:0.5 animations:^ {self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);}];
    
    self.activeKeyboardSize = CGSizeZero; }
    

    How everything starts:

    - (void) keyboardDidShow:(NSNotification*)notification {
    NSDictionary* info = [notification userInfo];
    self.activeKeyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    
    CGFloat tableViewBottom = self.tableView.frame.origin.y + self.tableView.frame.size.height;
    CGFloat keyboardTop = self.view.frame.size.height - self.activeKeyboardSize.height;
    CGFloat coveringVerticalSpace = tableViewBottom - keyboardTop;
    if (coveringVerticalSpace <= 0)
        return;
    
    TableViewScrollDirection scrollDirection = [self scrollToKeepEditingCellVisibleAboveVerticalPoint:self.tableView.frame.size.height - coveringVerticalSpace - UI_MARGIN_DEFAULT anchorsToVerticalPoint:NO];
    if (scrollDirection == TableViewScrollUp)
        self.textControlCellHadToMoveUpToBeVisibleOverKeyboard = YES;}
    

    The user may also jump its editing directly from one textField or textView in one cell to another in another cell without closing the keyboard. This must be taken into account and handled.

    The scrolling method should also be called whenever a textView text changes because in case its size and therefore the cell's size also need to change:

    CGFloat tableViewBottom = self.tableView.frame.origin.y + self.tableView.frame.size.height;
    CGFloat keyboardTop = self.view.frame.size.height - self.activeKeyboardSize.height;
    CGFloat coveringVerticalSpace = tableViewBottom - keyboardTop;
    if (coveringVerticalSpace <= 0)
        return;
    
    [self scrollToKeepEditingCellVisibleAboveVerticalPoint:self.tableView.frame.size.height - coveringVerticalSpace - UI_MARGIN_DEFAULT anchorsToVerticalPoint:self.textControlCellHadToMoveUpToBeVisibleOverKeyboard cellHeight:staticCellView.frame.size.height adjustsCellSize:adjustsCellSize]; // UI_MARGIN_DEFAULT is 8.0 and it gives a little margin of 8 points over the keyboard.
    

    Also useful:

    typedef NS_ENUM(NSUInteger, TableViewScrollDirection){
    TableViewScrollNone,
    TableViewScrollDown,
    TableViewScrollUp };
    

    A useful property to create in the viewController:

    @property (nonatomic) BOOL textControlCellHadToMoveUpToBeVisibleOverKeyboard;
    

    I hope this will be of use.

    0 讨论(0)
提交回复
热议问题