当 UITableViewController frame.height 较小时,UITableViewController refreshControl 出现故障

UITableViewController refreshControl is glitchy when UITableViewController frame.height is small

我遇到一个问题,原因是当 UITableViewController 的框架低于特定高度时,UITableViewController refreshControl 会出现故障。

就目前而言,我有一个 UIViewController,在其中我有一个嵌入了 UITableViewController 的 ContainerView。我希望高度为屏幕的 50%。

当我使用 refreshControl 时,出现这种行为:The tableView jumps down at the very end when scrolling down. You'll notice it towards the end of this video when I decide to scroll down slowly.

当ContainerView frame 高于某个值时,不会出现此问题。因此,当高度为屏幕的 75% 时,一切正常,refreshControl 也很流畅。当它是 50% 时,就会出现该错误。

我尝试了两种不同的方法:

  1. self.tableView.frame = CGRectMake(0, numOfPixelsToDropTableBy, self.tableView.frame.size.width, self.tableView.frame.size.height) 是我尝试过的一件事。这样做的问题是,如果您想通过 ContainerView 为 tableView 提供圆角,而您的 ContainerView 仍然占用更多 space 的事实,这会使其他元素的约束变得尴尬。

  2. 我去了故事板,我基本上在我想要的地方有了 ContainerView 的顶部。然后,我将底部延伸到屏幕底部之外,为 ContainerView 提供足够大的高度……但用户永远不会知道。除了,他们会知道,因为现在 tableView 超出了屏幕,我看不到 tableView 的最后几行。

最终...我不想使用第 3 方库,但我想要一个功能完美的 refreshControl。我该如何解决这个问题?

看来您几乎已经解决了您的问题(通过粗略的解决) 使用您的离屏 UIContainerView 尝试。再试一次,但这次 try:

  1. numberOfRowsInSection: 中的行数增加 1
  2. 在您的 cellForRowAtIndexPath: 方法中,将最后一个单元格的 rowHeight 属性 设置为容器视图在屏幕下方的距离。

第 2 步 如果您使用 tableView:heightForRowAtIndexPath: 方法将不起作用 - 相反,您需要使用其索引设置最后一个单元格的高度。使用此可选方法可能会导致严重的性能问题,并可能导致刷新控件滞后。

1.I已创建下一个架构

2.Added 一些约束

3.In TableViewController 我添加了下一个代码

import UIKit

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.refreshControl = UIRefreshControl(frame: CGRectZero)
        self.refreshControl!.addTarget(self, action: "refresh:", forControlEvents: .ValueChanged)
    }

    func refresh(sender:UIRefreshControl)
    {
        self.refreshControl?.endRefreshing()
    }
}
  1. 并将示例上传到 github

重要说明 我用过 Xcode 7 和 Swift 2。

我完全无意中重现了您的问题并设法解决了它,但代价是完全没有利润。

如果您对容器视图使用基于边距的约束或任何类型的边距,则似乎会发生跳跃。如果删除约束的边距相关部分,跳跃就会消失。

很奇怪,但似乎是问题所在。只要我为容器添加任何边距相对约束,问题 returns。移除它,显示恢复平滑滚动。

这似乎是一个错误,我认为您需要向 Apple 提交错误报告。

更新:

再看一遍,问题似乎在容器视图不是屏幕的全宽时就出现了。向容器视图添加任何类型的边距(通过相对于边距的布局或通过在约束上设置非零偏移)会导致跳跃行为。

更新:

如果 UITableView 在具有任何边距的容器视图内滚动,似乎会从根本上破坏某些东西。如果您覆盖滚动委托,则滚动视图的内容 offset/bounds 在刷新即将触发时正在更改。这是一些显示问题的调试

Start pulling down:

Scroll bounds = {{0, -127.33333333333333}, {374, 423}}
Scroll pos = [0.000000,-127.333333]
Scroll bounds = {{0, -127.66666666666667}, {374, 423}}
Scroll pos = [0.000000,-127.666667]
Scroll bounds = {{0, -128.33333333333334}, {374, 423}}
Scroll pos = [0.000000,-128.333333]

Ok before here ------->

Activity spinner becomes fully populated. Jump in scroll position upwards.

Scroll bounds = {{0, -104}, {374, 423}}
Scroll pos = [0.000000,-104.000000]

Scroll position corrects itself

Scroll bounds = {{0, -128.33333333333334}, {374, 423}}
Scroll pos = [0.000000,-128.333333]
Scroll position jumps the other direction by the same amount
Scroll bounds = {{0, -151.33333333333334}, {374, 423}}
Scroll pos = [0.000000,-151.333333]

Value changed target action fires. Bounds seem to reset (think 44 is height of refresh control

Scroll bounds = {{0, -44}, {374, 423}}
Scroll pos = [0.000000,-44.000000]
Corrects back
Scroll bounds = {{0, -151.33333333333334}, {374, 423}}
Scroll pos = [0.000000,-151.333333]
Fully corrects to the right scroll position by jumping back.

Ok after here ------>

Scroll bounds = {{0, -128.66666666666666}, {374, 423}}
Scroll pos = [0.000000,-128.666667]
Scroll bounds = {{0, -129}, {374, 423}}
Scroll pos = [0.000000,-129.000000]
Scroll bounds = {{0, -129.33333333333334}, {374, 423}}
Scroll pos = [0.000000,-129.333333]
Scroll bounds = {{0, -129.66666666666666}, {374, 423}}
Scroll pos = [0.000000,-129.666667]
Scroll bounds = {{0, -130}, {374, 423}}

结论

我似乎找不到解决此问题的简便方法。我尝试创建自己的 table 视图控制器,但跳跃消失了,但取而代之的是另一种效果:当您向下滚动时,顶部单元格消失,然后重新出现。我想它与同一个内部问题有关,只是表达方式不同。

不幸的是,您可能不得不忍受这种影响,或者不惜一切代价。我会向 Apple 提交错误报告。

唯一的选择是在 UITableViewCells 中创建边距。您可以使单元格内容视图具有清晰的背景,并使用单元格内容的内部容器视图为单元格引入左右边距。我认为这可能是你最好的机会。

最后...

为了不被打败,您可以对 table 视图的导航控制器应用缩放变换以创建边距,在您的 table 视图控制器中执行以下操作:

override func viewWillAppear(animated: Bool) {
  super.viewWillAppear(animated)

  // Add a scaling transform to the whole embedded controller view.      
  self.navigationController!.view.transform=CGAffineTransformMakeScale(0.9, 0.9);
}

这使得嵌入式控制器的视图看起来小了 90%,因此它在边框周围有一个边距。将比例更改为以更改边框大小。

不理想,但完美无缺,没有跳转滚动,而且有边框。随着整个内容的缩放,您还可以完全自由地使用圆角等。

跟进我的评论:

要让 UIRefreshControlUICollectionViewUITableView 我尝试了很多东西,但最后 UIRefreshControl 真的只在 UITableViewController.

还有一个问题是调整 UIRefreshControl: 的 tintColor 有时它会为微调器着色,有时不会,有时 tintColor 需要出于某种原因设置在动画块中才能生效。

所以我放弃了UIRefreshControl,实现了自己的解决方案。它不像在UITableViewController上设置UIRefreshControl那么简单,而是:

  • 它工作得很好(或者至少我没能找到未发现的边缘情况:如果你找到它们,请提交一个 pull-request)

  • 您可以实现任何类型的加载视图(旋转的东西,弹跳的东西,甚至可能是地图视图,或者一些 UIKit Dynamics ).

您可以在这里找到它:

JRTRefreshControl

我发现在 tableView 上设置 estimatedRowHeight 以匹配 rowHeight 即可解决问题。作为参考,我的设置是 UITableViewController 包含在 UIViewController 中,固定 rowHeight 为 140。