【问题标题】:Resize and move UITableViewCell smoothly without dismissing keyboard在不关闭键盘的情况下平滑地调整和移动 UITableViewCell
【发布时间】:2018-06-02 23:51:18
【问题描述】:

我在 UITableViewCell 中有一个 UITextView。当用户编辑 UITextView 文本时,我调整了 UITextView 的大小,我需要调整 UITableViewCell 的大小,并确保 UITableViewCell 始终位于键盘上方。

要在不关闭键盘的情况下调整 UITableViewCell 的大小,我正在执行以下操作,并且效果很好:

[tableView beginUpdates];
[tableView endUpdates];

要向上移动 tableView 并使单元格在键盘上方可见,我正在执行以下操作,它工作得很好:

[tableView setContentOffset:CGPointMake(0, myDesiredScrollOffset) animated:YES];

我的问题是我不能同时调整 UITableViewCell 的大小和平滑移动。这样的事情是行不通的:

[tableView beginUpdates];
[tableView endUpdates];
[tableView setContentOffset:CGPointMake(0, myDesiredScrollOffset) animated:YES];

如果我这样做,单元格会正确调整大小,但 tableView 会一直向下滚动。 我知道这种调整 UITableViewCell 大小的方式是异步工作的,这就是为什么调用 setContentOffset 不起作用的原因,可能是因为 iOS 在表格视图单元格调整大小处理过程的中间处理了 setContentOffset。

我尝试了以下操作,表格视图最终滚动到所需的位置。但是用户可以看到 tableView 上下移动,看起来很奇怪:

[tableView beginUpdates];
[tableView endUpdates];
[self performSelector:@selector(myMethodToScroll) withObject:nil afterDelay:0.01];

...

 - (void) myMethodToScroll {
[self.tableView setContentOffset:CGPointMake(0, self.myDesiredScrollOffset) animated:YES];}

非常感谢这个社区对我的问题的帮助,因为我已经为这个问题苦苦挣扎了几天。 这些测试是在装有 iOS 10 和 iOS 11 的设备上进行的,结果是一样的。

提前致谢。

【问题讨论】:

    标签: ios objective-c iphone uitableview uikeyboard


    【解决方案1】:

    我设法找出了如何做到这一点! 有 3 个非常重要的细节:

    1. 在不关闭键盘的情况下调整单元格大小的方式。 (正常重新加载会隐藏键盘)。
    2. 只有在内容偏移动画完成后才能设置单元格高度。 (否则 setContentOffset 可能会被忽略)。
    3. 为 tableView 设置底部插图。 (否则调整单元格大小可能会向下滚动表格,隐藏我们希望在键盘上方可见的单元格。)

    此方案已在 iOS10 和 iOS11 中使用真 iPhone 进行测试。

    下面是方法(所有代码都在 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;}
    

    技巧的第二部分在于仅在滚动动画结束后调整单元格大小:

    - (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];
    }];}
    

    很重要:键盘关闭后,平滑重新调整tableview滚动(如有必要):

    - (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; }
    

    一切如何开始:

    - (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;}
    

    用户也可以直接从一个单元格中的一个 textField 或 textView 跳转到另一个单元格中的另一个,而无需关闭键盘。必须考虑和处理这一点。

    每当 textView 文本发生变化时,也应该调用滚动方法,因为它的大小和单元格的大小也需要改变:

    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.
    

    也很有用:

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

    在 viewController 中创建一个有用的属性:

    @property (nonatomic) BOOL textControlCellHadToMoveUpToBeVisibleOverKeyboard;
    

    我希望这会有用。

    【讨论】:

      【解决方案2】:

      在单元格中从上到下正确挂钩约束也不实现 heightForRowAtIndexpath

      然后

      在 viewDidLoad 中

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

      在数据源中

        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
      
      }
      

      【讨论】:

      • 对不起……这个 self.tableViewBottomcon.constant 是什么?
      • tableView的底部约束将其拖为IBOutlet
      • 我的表格视图是以编程方式创建的。我相信 IBOutlet 不会在这里工作......
      • 我的问题是没有设置内容偏移量。我的问题是根据用户类型调整单元格的大小,同时进行偏移。请阅读我的帖子。
      • 尝试动态单元格高度
      猜你喜欢
      • 2016-02-20
      • 2019-12-21
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      • 2012-09-16
      • 2011-07-17
      • 1970-01-01
      • 2018-01-18
      相关资源
      最近更新 更多