无需关闭键盘即可平滑调整大小并移动UITableViewCell [英] Resize and move UITableViewCell smoothly without dismissing keyboard

查看:117
本文介绍了无需关闭键盘即可平滑调整大小并移动UITableViewCell的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 the UITableViewCell is always above the keyboard.

调整UITableViewCell的大小在没有解雇键盘的情况下,我正在做以下工作并且工作正常:

To resize the UITableViewCell without dismissing the keyboard I am doing the following and it works just fine:

[tableView beginUpdates];
[tableView endUpdates];

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

To move the tableView up and have the cell visible above the keyboard I am doing the following and it works just fine:

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

我的问题是我不能同时调整UITableViewCell的大小并顺利移动。这样的东西不起作用:

My problem is that I cannot both have the UITableViewCell resized and moved smoothly together. Something like this will not work:

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

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

If I do it, the cell gets properly resized but the tableView scrolls all the way down instead. I understand that this way of resizing the UITableViewCell works asynchronously and that is why calling setContentOffset will not work, probably because the setContentOffset is being handled in the middle of the table view cell resizing handling process by iOS.

我尝试了以下内容,并且tableview最终滚动到所需的位置。但是,用户可以看到tableView上下移动,看起来很奇怪:

I than tried the following and the tableview ends up scrolling to the desired place. However the user can see the tableView go up and down and it looks strange:

[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的设备上进行的,结果是相同的。

I would greatly appreciate help of this community on my problem because I have been struggling with this problem for a few days already. These tests are being made on devices with iOS 10 and iOS 11 and the results are the same.

提前致谢。

推荐答案

我设法找到了怎么做!
有3个非常重要的细节:

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


  1. 在不关闭键盘的情况下调整单元格大小的方式。 (正常重新加载将隐藏键盘)。

  2. 仅在内容偏移动画完成后才设置单元格高度。 (否则可以忽略setContentOffset)。

  3. 为tableView设置底部插图。 (否则调整单元格大小可能会向下滚动表格,隐藏我们想要在键盘上方可见的单元格。)

此解决方案已被在iOS10和iOS11中使用真实的iPhone进行了测试。

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

以下是(所有代码在viewController中实现):

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

非常重要:键盘关闭后,顺利重新调整tableview滚动(如有必要):

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

一切如何开始:

- (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跳转到另一个单元格中的另一个单元格,而无需关闭键盘。这必须考虑并处理。

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.

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

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.

也很有用:

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

在viewController中创建的有用属性:

A useful property to create in the viewController:

@property (nonatomic) BOOL textControlCellHadToMoveUpToBeVisibleOverKeyboard;

我希望这是有用的。

这篇关于无需关闭键盘即可平滑调整大小并移动UITableViewCell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆