Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIRefreshControl Stuck After Switching Tabs in UITabBarController

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.

like image 861
Justin Ling Avatar asked Jun 21 '14 11:06

Justin Ling


6 Answers

I know this is incredibly late, but I figure better late than never.

Unfortunately, none of the given answers worked for me. The only thing that worked was this awful piece of code in viewWillAppear:

self.refreshControl = nil;
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refreshFunction) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;

Basically I recreate the UIRefreshControl every time the view is going to appear. It works, albeit while giving the following warning:

Attempting to change the refresh control while it is not idle is strongly discouraged and probably won't work properly.

I'm honestly surprised this is still an issue (still seeing this in iOS 9 now). Hopefully this may be helpful to some other people.

like image 172
Justin Ling Avatar answered Oct 17 '22 13:10

Justin Ling


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.

like image 42
user3006173 Avatar answered Oct 17 '22 11:10

user3006173


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

like image 6
Ivan Rep Avatar answered Oct 17 '22 13:10

Ivan Rep


The following solution may help you.

CGFloat yTableViewOffset;

- (void)viewDidLoad {

      yTableViewOffset = kNilOptions;
}
- (void)viewWillAppear:(BOOL)animated
{
   if(yTableViewOffset != kNilOptions) {

     CGPoint offset = CGPointMake(tableView.contentOffset.x, yTableViewOffset);
     [refreshControl beginRefreshing];
     tableView.contentOffset = offset;

  }
}
- (void)viewWillDisappear:(BOOL)animated
{
   if(refreshControl.isRefreshing) {
     yTableViewOffset = tableView.contentOffset.y;
     [refreshControl endRefreshing];
  }
}
like image 4
Prasanna Avatar answered Oct 17 '22 12:10

Prasanna


Simply calling endRefreshing in viewWillDisappear: fixed all the issues for me.

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.refreshControl endRefreshing];        
}

Doing the same thing in viewWillAppear: caused the refresh control to rotate strangely when pulling the table.

like image 4
maxkonovalov Avatar answered Oct 17 '22 12:10

maxkonovalov


You can try

refreshControl.beginRefreshing()
refreshControl.endRefreshing()

in viewWillAppear, and this should work.

like image 3
Jay He Avatar answered Oct 17 '22 11:10

Jay He