UIRefreshControl Stuck After Switching Tabs in UIT

2019-01-17 20:28发布

I have a UITableViewController as the root view controller in a UINavigationController, which is in turn one of the view controllers in a UITabBarController. All hooked up in Storyboard.

I've configured the UIRefreshControl for my table in Storyboard as well, and normally it looks like it should when pulling:

Normal UIRefreshControl

However, if I switch between my other tabs once or twice, it looks like this:

Buggy UIRefreshControl

It's not spinning or anything, just stuck "full", and it stays that way until I pull fully and trigger a refresh.

Any ideas or suggestions appreciate.

16条回答
来,给爷笑一个
2楼-- · 2019-01-17 21:01

I could not get the call to endRefreshing to work before the navigation happened so I approached the problem from the other end and on viewWillAppear I check if the tableView contentOffset is a negative number bring the tableView back to 0.

 - (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (self.tableView.contentOffset.y < 0)
    {
        [self.tableView setContentOffset:CGPointZero animated:YES];
    }
}
查看更多
▲ chillily
3楼-- · 2019-01-17 21:02

I want some points and like Albert solution but not his style.

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    _table.contentOffset = CGPointMake(_table.contentOffset.x, _table.contentOffset.y + 1.0f);
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    _table.contentOffset = CGPointMake(_table.contentOffset.x, _table.contentOffset.y - 1.0f);
}
查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-01-17 21:02

I was able to solve this issue by placing the following piece of code in viewWillDisappear

    DispatchQueue.main.async {
        self.refreshControl.beginRefreshing()
        self.refreshControl.endRefreshing()
    }

If the above code is placed in viewWillAppear then spinner will animate and dismiss within a fraction of seconds, in either of the cases the issue will be solved but however, in users point of view the spinner should not be visible so, it's better to place it in viewWillDisappear.

查看更多
Fickle 薄情
5楼-- · 2019-01-17 21:04

I have a collectionView, and I did set it's contentInset.

When pushing some ViewControllers, then press home button, and go back and pop back, the UIRefreshControl is always on the top.

Finally I use this code temporarily avoid it. (Ugly but stops it always shows on top)

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self.refreshControl endRefreshing];

    CGPoint currentContentOffset = self.collectionView.contentOffset;

    [self.collectionView setContentOffset:CGPointMake(currentContentOffset.x,
                                                      currentContentOffset.y - 1.0f)
                                 animated:YES];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    CGPoint currentContentOffset = self.collectionView.contentOffset;

    [self.collectionView setContentOffset:CGPointMake(currentContentOffset.x,
                                                      currentContentOffset.y + 1.0f)
                                 animated:YES];
}
查看更多
欢心
6楼-- · 2019-01-17 21:06

To sum up and provide a complete solution.

The problem:

If UIRefreshControl is animating during screen transition, it will stay visible but will not be animating. Video https://vid.me/Bkb7

Also, if pull to refresh animation was started but not completed, and then transition was performed, UIRefreshControl will be hidden but stuck. Video https://vid.me/Bkb7

Solution:

Start UIRefreshControl animation on viewWillAppear and end it on viewDidDisappear. Save the state of refresh process to know when to show UIRefreshControl.

Bellow is the whole solution that also handles the proper animation and simple pull to refresh animation.

Add to UITableView or subclass

Initialization:

 /// Refresh indicator
var refreshControl = UIRefreshControl()

/// Refresh state
var isRefreshing = false

/// Refresh controll update funcion. Set to enable pull to refresh
var refreshControllUpdateFunction: (() -> ())?

/// Prepeares UIRefreshControll. Call from init
func initRefreshControl(){
    addSubview(refreshControl)

    refreshControl.addTarget(self, action: "refreshControllTarget", forControlEvents: .ValueChanged)
    refreshControl.beginRefreshing()

    isRefreshing = true
}

Superview event handlers:

/// Call on viewWillApper
func superviewWillApper(){
    if isRefreshing && !refreshControl.refreshing{
        startRefreshAnimation()
    }
}

/// Call on viewDidDisapper
func superviewDidDisappear(){
    endRefreshAnimation(false, dataFetched: !isRefreshing)
}

UIRefreshControl animation handler:

/// Presents animating UIRefreshControll
func startRefreshAnimation(){
    refreshControl.beginRefreshing()
    contentOffset = CGPointMake(0, -refreshControl.bounds.size.height)

    isRefreshing = true
}

/// Hides UIRefreshControll and saves state of refresh
func endRefreshAnimation(wasEmpty: Bool, dataFetched: Bool){
    refreshControl.endRefreshing()

    isRefreshing = !dataFetched

    if !wasEmpty{
        setContentOffset(CGPointZero, animated: true)
    }else{
        setContentOffset(CGPointZero, animated: false)
    }
}

Add

table.isRefreshing = true

to begining of the refresh call.

Result video https://vid.me/LyuI

查看更多
疯言疯语
7楼-- · 2019-01-17 21:07

user2009606 was almost right, I fixed it by calling

[refreshControl endRefreshing];

On

viewWillAppear:

The refreshControl now behaves properly after switching tabs, independent of its state.

查看更多
登录 后发表回答