UITableView dragging distance with UIRefreshContro

2020-08-26 13:58发布

I'm having some trouble on implementing a UIRefreshControl on a UITableView.

Everything is working fine except the fact that I have to scroll something like 80% of the screen for the UIRefreshControl to get triggered. Sometimes I'm not even able to trigger it since there is a tab bar on the bottom of the screen, which cancels the scrolling movement when the finger reaches it.

I've looked at other apps, namely Apple's 'Mail', where the UIRefreshControl is triggered after scrolling only 30% of the screen.

What am I missing? Really need help on this one!

Thanks in advance

3条回答
beautiful°
2楼-- · 2020-08-26 14:11

You probably need to not use UIRefreshControl and just utilize scrollViewDidScroll (or tableViewDidScroll if a tableView) on handle your refresh accordingly since UIRefreshControl can't be modified.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if ((scrollView.contentOffset.y + scrollView.frame.size.height) >=    scrollView.contentSize.height)
    {
        // Refresh from here
    }
}
查看更多
家丑人穷心不美
3楼-- · 2020-08-26 14:15

I had a similar problem and it's quite possible that's the same cause for you. For me happens that I hided the scroll indicator making me unable to see the obvious cause of the problem: the UIScrollView's height is much greater than its superView...

Double check your UIScrollView's height because the "dragging distance" it's just a percentage of that height. Same goes for UITableView too, since it's a child class of UIScrollView.

EDIT: Seems that this isn't the only way to reproduce this problem, since the required drag distance to trigger the refresher is calculated in a buggy way. Refer to this question for more info.

But in general it will happen if your UIScrollView's height is different than his parent container (e.g the screen itself).

查看更多
Emotional °昔
4楼-- · 2020-08-26 14:24

After some extensive testing and playing around with UIKit I have come to a conclusion.

TL;DR

UIRefreshControl isn't smart enough. To fix add this code in viewDidAppear or viewDidLayoutSubviews

let refreshControl = scrollView.refreshControl
scrollView.refreshControl = nil
scrollView.refreshControl = refreshControl

Test setup

Single UIViewController in a Storyboard with a UIView as its view which in turn has a UIScrollView as only subview which in turn has a single UIView as subview with top,right,bottom,left,width,height constraints equal to superview. The viewController has freeform size with 1200p height.

In the subclass of the UIViewController a UIRefreshControl is added by setting the UIScrollView#refreshControl to a new UIRefreshControl inside viewDidLoad.

When running the application in an iPhone X simulator and dragging the scrollView to perform a "Pull to refresh" one must drag considerably longer to make the refreshControl animating and send its notification it was pulled down.

The problem

One of my hypotheses was that the UIRefreshControl gets its dragging distance set once it is added to the scrollView and since AutoLayout hasen't updated the root view's subviews at viewDidLoad the scrollView has a height of 1180.0p instead of the correct 768.0p thus the refreshControl's dragging distance would be calculated for the height 1180.0p instead of 768.0p and thus become much longer than expected when running the app.

The solution

By updating the scrollView's refreshControl after the correct size for the scrollView has been set the correct dragging distance is calculated.

This update has to occur in a function where the correct size of the scrollView has been calculated, for example viewDidAppear and viewDidLayoutSubviews.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    let refreshControl = scrollView.refreshControl
    scrollView.refreshControl = nil
    scrollView.refreshControl = refreshControl
}
查看更多
登录 后发表回答