如何修复或解决此tableView textField autolayout故障?

时间:2016-12-08 01:32:38

标签: ios objective-c uitableview autolayout

我认为根本原因是estimatedRowHeight用于对基础UIScrollView.contentOffset做出假设,但这定义总是错误的,因为它是一个估计。实际行高度完全不同,具体取决于单元格内容和设备方向。

即使我实施estimatedHeightForRowAtIndexPath以提供更接近的估计,故障仍然存在。

因此,当您从顶部开始向下滚动时,一切都很顺利,因为TableView会了解实际的单元格高度,因为它会使contentOffset与单元格位置保持同步。但是一旦你旋转所有真实的单元格高度变化,所以UITableView现在不同步,它不知道滚动到哪里。

但是甚至有些奇怪的事情发生了,有时候UITextField单元格最终会出现在另一个单元格的顶部,并且仍然卡在那里......

无论如何,我把它简化为一个简单的例子。

https://github.com/trapper-/autolayout-glitch

  • 使用iPhone测试,如果使用模拟器,则启用软件键盘。
  • 你会看到许多视觉故障只是围绕滚动,选择字段和旋转。
  • 简单的可重复示例。
  • 向下滚动到底部。
  • 选择最后几个UITextField's中的一个,以便UITableView需要滚动以确保该字段可见。
  • 旋转设备。

3 个答案:

答案 0 :(得分:1)

我玩了你的代码几分钟,因为我在类似的问题上挣扎。我希望我可以提供帮助,但我并没有完全修复它。

我能提供的是我确实做了一些进展。

当设备旋转时,你应该实现UIViewcontroller方法,告诉你它会发生,并且确实发生了。当它发生时,缓存可见行。然后,重新加载表并滚动到那些可见的行。

看起来像这样:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    // Save the visible row position
    self.visibleRows = [self.tableView indexPathsForVisibleRows];
}

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self.tableView reloadData];
    // Scroll to the saved position prior to screen rotate
    [self.tableView scrollToRowAtIndexPath:[self.visibleRows objectAtIndex:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}

visibleRows是ViewController上的数组@property。

这使它进入了正确的位置(我怀疑如果你实际存储了用户正在操作的单个单元格,那么每次都会让你100%到达正确的单元格。

这没有做到的是,仍有一些跳舞的UITextField错误地(有时)布置了多个设备轮换。

同样,不是解决方案 - 但我想分享我所看到的内容,希望这有助于您找到解决方案。

祝你好运!

答案 1 :(得分:0)

我很确定你的问题在于:

self.tableView.estimatedRowHeight = 44;

这会导致tableview围绕此估计高度进行一些优化。我无法弄清楚为什么在选择文本字段时这会中断,但这就是我设法将其缩小到的范围。如果你确实明确地计算了每一行的高度,那么这个问题似乎就会消失(请注意,这只是一个粗略的例子,你需要在实际的实现中加入一点思考):

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (indexPath.row % 2) {

        return 44.f;

    } else {

        NSString *text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

        CGRect frame = [text boundingRectWithSize:CGSizeMake(350.f, CGFLOAT_MAX)
                                          options:NSStringDrawingUsesLineFragmentOrigin
                                       attributes:@{ NSFontAttributeName:[UIFont systemFontOfSize:14.f] }
                                          context:nil];

        return frame.size.height;
    }
}

答案 2 :(得分:0)

我看了看那个项目。我最好的建议是减少一些问题,以改善您的估计身高计算。如果文本视图单元格会更大,那么估计的高度需要更接近单元格的平均高度,因此在旋转时,调整大小会更少。

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath (NSIndexPath *)indexPath 
{
    if (indexPath.row % 2) {
        return 44.0f;
    } else {
        return 175.0f;
    }
}

现在关于UITextField的奇怪问题,我认为您可能需要考虑这些单元格即使在旋转时也会被重用,所以如果UITextField仍然是第一响应者,即使该单元格已经被重用,那么这就是键盘无法跟踪文本字段。

您可以通过在单元格上设置标记来查看此结果,并观察它如何随机更改旋转顺序,如下所示:

NSString* cellID = @"TextFieldCell";
TextFieldCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
NSLog(@"cell %@, changing to %@", @(cell.tag), @(indexPath.row));
cell.tag = indexPath.row;
return cell;

我的建议是:1)不使用表格视图单元格中的文本字段,或者2)想出一种让用户在滚动项目上输入文本的新方法。例如,将文本字段副本放在表视图顶部的视图中,并在输入文本时手动管理,然后在文本完成时将文本复制回单元格。 3)选项3是试图查看键盘管理器库是否有帮助。我真的很喜欢使用IQKeyboardManager。这对解决键盘管理非常方便。