简体   繁体   English

当UITableViewController frame.height很小时,UITableViewController refreshControl很麻烦

[英]UITableViewController refreshControl is glitchy when UITableViewController frame.height is small

I have a problem that stems from the fact that UITableViewController refreshControl is glitchy when the frame of the UITableViewController is below a certain height. 我有一个问题,因为当UITableViewController的帧低于某个高度时,UITableViewController refreshControl很麻烦。

As it stands, I have a UIViewController, and in it I have a ContainerView that embeds a UITableViewController. 就目前而言,我有一个UIViewController,在其中我有一个嵌入UITableViewController的ContainerView。 I want the height to be 50% of the screen. 我希望高度为屏幕的50%。

When I use the refreshControl, I get this kind of behavior: The tableView jumps down at the very end when scrolling down. 当我使用refreshControl时,我会遇到这种行为: 当向下滚动时,tableView会在最后跳转。 You'll notice it towards the end of this video when I decide to scroll down slowly. 当我决定慢慢向下滚动时,你会注意到这段视频的结尾。

This problem does not occur when the ContainerView frame is above a certain value. 当ContainerView框架高于某个值时,不会发生此问题。 So, when the height is 75% of the screen, everything works perfectly and the refreshControl is smooth. 因此,当高度为屏幕的75%时,一切都运行良好,refreshControl也很流畅。 When it is 50%, then that bug happens. 当它是50%时,则发生该错误。

Two different things I have tried: 我尝试了两件不同的事情:

  1. self.tableView.frame = CGRectMake(0, numOfPixelsToDropTableBy, self.tableView.frame.size.width, self.tableView.frame.size.height) is one thing that I tried. self.tableView.frame = CGRectMake(0, numOfPixelsToDropTableBy, self.tableView.frame.size.width, self.tableView.frame.size.height)是我尝试过的一件事。 The problem with this is if you want to give the tableView rounded corners via the ContainerView and the fact that your ContainerView still takes up more space and this makes constraints for other elements awkward. 这个问题是如果你想通过ContainerView给tableView圆角以及你的ContainerView仍然占用更多空间这一事实,这使得其他元素的约束变得尴尬。

  2. I went to the Storyboard and I basically had the top of the ContainerView where I wanted. 我去了故事板,我基本上拥有了我想要的ContainerView的顶部。 Then, I had the bottom extend beyond the bottom of the screen to give the ContainerView a large enough height... but the user would never know. 然后,我将底部延伸到屏幕底部以外,为ContainerView提供足够大的高度......但用户永远不会知道。 Except, they would know because now the tableView extends beyond the screen and I can't see the last few rows of my tableView. 除此之外,他们会知道,因为现在tableView超出了屏幕,我无法看到tableView的最后几行。

Ultimately... I don't want to use a 3rd-party library, but I want a perfectly functioning refreshControl. 最终......我不想使用第三方库,但我想要一个功能完善的refreshControl。 How can I fix this? 我怎样才能解决这个问题?

1.I've created next architecture 1.我创建了下一个架构
在此输入图像描述
2.Added some constraints 2.增加了一些限制
在此输入图像描述
3.In TableViewController I've added next code 3.在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. And uploaded example to github 并上传到github的示例

IMPORTANT NOTE I've used Xcode 7 and Swift 2. 重要说明我使用过Xcode 7和Swift 2。

I managed to recreate your issue exactly by accident and managed to fix it, but at the cost of having no margins at all. 我设法完全意外地重新创建了你的问题,并设法修复它,但代价是根本没有利润。

The jumping seems to happen if you use margin based constraints or any kind of margin for your container view. 如果您对容器视图使用基于边距的约束或任何类型的边距,则似乎会发生跳跃。 If you remove the margin relative part of the constraints, the jumping disappears. 如果删除约束的边距相对部分,则跳跃消失。

Very strange, but seems to be the issue. 很奇怪,但似乎是问题。 As soon as I add any margin relative constraint for the container, the issue returns. 只要我为容器添加任何边距相对约束,问题就会返回。 Removing it and the display goes back to smooth scrolling. 删除它,显示屏返回平滑滚动。

This would seem to be a bug and I think you will need to raise a bug report with Apple. 这似乎是一个错误,我认为你需要向Apple提出错误报告。

Update: 更新:

Looking again, the issue seems to appear as soon as the container view is not the full width of the screen. 再看一下,只要容器视图不是屏幕的整个宽度,问题就会出现。 Adding any sort of margin to the container view (via layout relative to margin or by setting a non zero offset on a constraint) results in the jumpy behavior. 向容器视图添加任何类型的边距(通过相对于边距的布局或通过在约束上设置非零偏移)会导致跳跃行为。

Update: 更新:

Something would appear to be fundamentally broken with UITableView scrolling inside a container view which has any kind of margin. UITableView在具有任何边距的容器视图内滚动,似乎会从根本上破坏某些东西。 If you override the scrolling delegate, the content offset/bounds of the scroll view are being changed at the moment the refresh is about to trigger. 如果覆盖滚动委托,则在刷新即将触发时正在更改滚动视图的内容偏移/边界。 Here is some debug showing the issue 这是一些显示问题的调试

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

Conclusion 结论

There seems to be no easy way I can find to work around this. 似乎没有简单的方法可以解决这个问题。 I tried creating my own table view controller and the jumping goes away but is replaced by a different effect: that being that when you scroll down the top cell disappears, then reappears. 我尝试创建自己的表视图控制器,跳跃消失但被另一种效果取代:当你向下滚动顶部单元格消失时,然后重新出现。 I imagine it relates to the same internal issue, just being expressed differently. 我想它与同一个内部问题有关,只是表达方式不同。

Unfortunatley looks like you might have to put up with the effect or go for no margin. Unfortunatley看起来你可能不得不忍受这种效果或者没有利润。 I would raise a bug report with Apple. 我会向Apple提出错误报告。

Only alternative option would be to create the margins in your UITableViewCells. 只有替代选项是在UITableViewCells中创建边距。 You could make the cell content view have a clear background and introduce a left and right margin to your cells using an internal container view for your cell content. 您可以使单元格内容视图具有清晰的背景,并使用内容容器视图为您的单元格引入左右边距。 I think that may be you best chance. 我想这可能是你最好的机会。

And Finally... 最后......

Not to be defeated, you can apply a scaling transform to the navigation controller for the table view to create a margin doing the following in your table view controller: 不要失败,您可以将缩放变换应用于表视图的导航控制器,以在表视图控制器中创建执行以下操作的边距:

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

This makes the view for the embedded controller appear 90% smaller so it has a margin around the border. 这使得嵌入式控制器的视图看起来小了90%,因此边界周围有一个边距。 Change the scale to to change the border size. 将比例更改为更改边框大小。

Not ideal, but works perfectly with no jump scrolling and has a border. 不理想,但没有跳跃滚动和边框的完美工作。 It also leaves you totally free to use rounded corners etc as the whole content is scaled. 它还可以让您完全自由地使用圆角等,因为整个内容都是缩放的。

It seems that you've almost solved your problem (with a rough work around) using your off screen UIContainerView attempt. 您似乎已经使用屏幕外UIContainerView尝试几乎解决了您的问题(使用粗略的工作) Give it another shot, but this time try : 给它另一个镜头,但这一次尝试

  1. Increasing the row count within the numberOfRowsInSection: by 1 . 增加numberOfRowsInSection:的行数numberOfRowsInSection: 1
  2. Inside your cellForRowAtIndexPath: method, set the last cell's rowHeight property to the distance your Container View is below the screen. 在您的cellForRowAtIndexPath:方法中,将最后一个单元格的rowHeight属性设置为Container View在屏幕下方的距离。

Step 2 won't work if you're using the method tableView:heightForRowAtIndexPath: - Instead, you'll need to set the height of the last cell using its index. 如果您使用方法tableView:heightForRowAtIndexPath: 步骤2 将不起作用tableView:heightForRowAtIndexPath: - 您需要使用其索引设置最后一个单元格的高度。 Using this optional method can cause significant performance problems and can lead to lagged Refresh Controls too. 使用此可选方法可能会导致严重的性能问题,并且还可能导致滞后的刷新控件。

Following up on my comment: 跟进我的评论:

To get UIRefreshControl it to play nicely with a UICollectionView or UITableView I've tried many things, but in the end the UIRefreshControl really only works well in a UITableViewController . 为了获得UIRefreshControl它可以很好地使用UICollectionViewUITableView我尝试了很多东西,但最后UIRefreshControl真的只适用于UITableViewController

Then there is also an issue with adjusting the tintColor of the UIRefreshControl: sometimes it colors the spinner, sometimes it doesn't, sometimes the tintColor needs to be set inside an animation-block for some reason to take effect. 然后还有调整UIRefreshControl:的tintColor的UIRefreshControl:有时它会为微调器UIRefreshControl: ,有时它不会,有时tintColor需要在动画块中设置,因为某些原因才能生效。

So I gave up on UIRefreshControl , and implemented my own solution. 所以我放弃了UIRefreshControl ,并实现了我自己的解决方案。 It is not as simple as setting a UIRefreshControl on a UITableViewController , but: UIRefreshControlUITableViewController上设置UIRefreshControl那么简单,但是:

  • it works perfectly (or at least I have not been able to find uncovered edge-cases: if you find them, please file a pull-request) 它完美地工作(或者至少我没能找到未发现的边缘情况:如果你找到它们,请提出拉动请求)

  • you can implement any kind of loading view (something that rotates, something that bounces, maybe even a map view, or some UIKit Dynamics ). 你可以实现任何类型的加载视图(旋转的东西,反弹的东西,甚至是地图视图,或者一些UIKit Dynamics )。

You can find it here: 你可以在这里找到它:

JRTRefreshControl JRTRefreshControl

I've found cases where simply setting an estimatedRowHeight on the tableView to match the rowHeight resolves the glitch. 我发现只需在tableView上设置一个estimatedRowHeight来匹配rowHeight解决故障。 For reference, my setup was a UITableViewController contained inside a UIViewController with a fixed rowHeight of 140. 作为参考,我的设置是一个UITableViewController包含在UIViewController ,固定的rowHeight为140。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM