为什么我的UITableView“跳转”插入或删除行时? [英] Why does my UITableView "jump" when inserting or removing a row?

查看:104
本文介绍了为什么我的UITableView“跳转”插入或删除行时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(很高兴接受Swift或Objective-C的回答)

(Happy to accept an answer in Swift or Objective-C)

我的表视图有几个部分,当按下按钮时,我想插入第0部分末尾的一行。再次按下按钮,我想删除同一行。我几乎正常工作的代码如下所示:

My table view has a few sections, and when a button is pressed, I want to insert a row at the end of section 0. Pressing the button again, I want delete that same row. My almost working code looks like this:

// model is an array of mutable arrays, one for each section

- (void)pressedAddRemove:(id)sender {
    self.adding = !self.adding;  // this is a BOOL property
    self.navigationItem.rightBarButtonItem.title = (self.adding)? @"Remove" : @"Add";

    // if adding, add an object to the end of section 0
    // tell the table view to insert at that index path

    [self.tableView beginUpdates];
    NSMutableArray *sectionArray = self.model[0];
    if (self.adding) {
        NSIndexPath *insertionPath = [NSIndexPath indexPathForRow:sectionArray.count inSection:0];
        [sectionArray addObject:@{}];
        [self.tableView insertRowsAtIndexPaths:@[insertionPath] withRowAnimation:UITableViewRowAnimationAutomatic];

    // if removing, remove the object from the end of section 0
    // tell the table view to remove at that index path

    } else {
        NSIndexPath *removalPath = [NSIndexPath indexPathForRow:sectionArray.count-1 inSection:0];
        [sectionArray removeObject:[sectionArray lastObject]];
        [self.tableView deleteRowsAtIndexPaths:@[removalPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }
    [self.tableView endUpdates];
}

这有时会表现正常,但有时不行,具体取决于表格视图的位置滚动:

This behaves properly sometimes, but sometimes not, depending on where the table view is scrolled:


  • 最上面的第0部分,contentOffset.y == 0:工作得很好,插入了行以及下面的内容0向下动画

  • 第0部分不可见,因为表格滚过它:效果很好,新行下面的可见内容向下动画,好像在它上面插入了一行。

  • 但是:如果表视图滚动了一点,那么部分0的部分是可见的:它工作错误。在单个帧中,表视图中的所有内容都会跳转(内容偏移量增加)然后,通过动画,插入新行并且表视图内容向下滚动(内容偏移减少)。一切都应该在它应该的地方结束,但是这个过程看起来非常糟糕,那个单帧在开始时跳。

我可以通过Debug-> Toggle Slow Animations在慢速运动模拟器中看到这种情况。在删除时反向出现同样的问题。

I can see this happen in slow-motion the simulator with "Debug->Toggle Slow Animations". The same problem occurs in reverse on the deletion.

我发现偏移量的跳跃大小与表格滚动到第0部分的距离有关:当偏移很小时跳跃很小。当滚动接近第0部分总高度的 half 时,跳跃变得更大(问题在于它在这里最差,跳跃= =部分高度的一半)。进一步滚动,跳跃变小。当滚动表格以便只能看到少量的0部分时,跳跃很小。

I've found that the size of the jump in offset is related to the how far into section 0 the table is scrolled: the jump tiny when the offset is tiny. The jump gets bigger as the scrolling approaches half of section 0 total height (the problem is at it's worst here, jump == half the section height). Scrolling further, the jump gets smaller. When the table is scrolled so that only a tiny amount of section 0 is still visible, the jump is tiny.

你能帮我理解为什么会这样吗?如何解决?

推荐答案

在iOS 11上,UITableView使用估计的行高作为默认值。

On iOS 11, UITableView uses estimated row height as default.

在插入/重新加载或删除行时会导致不可预测的行为,因为UITableView在大多数情况下的内容大小都是错误的:

It leads to unpredictable behaviors when inserting/reloading or deleting rows because the UITableView has a wrong content size most of the time :

为了避免过多的布局计算,tableView只为每个 cellForRow 调用 heightForRow 调用并记忆它(在正常模式下,tableView要求tableView的所有indexPathes的 heightForRow )。其余单元格的高度等于 estimatedRowHeight 值,直到调用相应的 cellForRow

To avoid too many layout calculations, the tableView asks heightForRow only for each cellForRow call and memories it (in normal mode, the tableView asks heightForRow for all the indexPathes of the tableView). The rest of the cells has a height equal to the estimatedRowHeight value until their corresponding cellForRow is called .

// estimatedRowHeight mode
contentSize.height = numberOfRowsNotYetOnScreen * estimatedRowHeight + numberOfRowsDisplayedAtLeastOnce * heightOfRow

// normal mode
contentSize.height = heightOfRow * numberOfCells

一种解决方案是禁用<$ c通过将estimatedRowHeight设置为0并为每个单元格实现 heightForRow ,$ c> estimatedRowHeight 模式。

One solution is to disable the estimatedRowHeight mode by setting estimatedRowHeight to 0 and implementing heightForRow for each of your cells.

当然,如果您的单元格具有动态高度(大部分时间都使用繁重的布局计算,因此您使用 estimatedRowHeight 一个很好的理由),您必须找到一种方法来重现 estimatedRowHeight 优化,而不会影响tableView的contentSize。请查看 AsyncDisplayKit UITableView-FDTemplateLayoutCell

Of course, if your cells have dynamic heights (with onerous layout calculations most of time so you used estimatedRowHeight for a good reason), you would have to find a way to reproduce the estimatedRowHeight optimization without compromising the contentSize of your tableView. Take a look at AsyncDisplayKit or UITableView-FDTemplateLayoutCell.

另一个解决方案是尝试查找 estimatedRowHeight 哪个适合。特别是在iOS 11上,您可以尝试对estimatedRowHeight使用 UITableViewAutomaticDimension

Another solution is to try to find a estimatedRowHeight which suits well. On iOS 11, in particular, you can try to use UITableViewAutomaticDimension for estimatedRowHeight :

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = UITableViewAutomaticDimension

这篇关于为什么我的UITableView“跳转”插入或删除行时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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