문제

I use UIRefreshControl in a UITableView:

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

With refresh handler:

-(void)refresh {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // (...some long running operation...)
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.refreshControl endRefreshing];
        });
    });
}

During the long running operation I make the application inactive pressing Home button. After that I make the application active again. The spinner freezes (stops spinning) and there is no way to return it to the initial state.

How to fix it?

도움이 되었습니까?

해결책

I think it is a bit delayed answer but , today I saw similar issue on ios 7 , ios 6 continued spinning ,

here is a little workaround for this

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    if(self.refreshControl.isRefreshing) {
        CGPoint offset = self.tableView.contentOffset;
        [self.refreshControl endRefreshing];
        [self.refreshControl beginRefreshing];
        self.tableView.contentOffset = offset;
    }
}

it will stop and start again spinning , but it only happened on ios7 with me , so maybe you should check not to do it on ios6

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    if(self.refreshControl.isRefreshing && [[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        CGPoint offset = self.tableView.contentOffset;
        [self.refreshControl endRefreshing];
        [self.refreshControl beginRefreshing];
        self.tableView.contentOffset = offset;
    }
}

다른 팁

This is what worked for me

Swift 3 and Swift 4:

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

    if self.refreshControl?.isRefreshing == true {
        let offset = self.tableView.contentOffset

        self.refreshControl?.endRefreshing()
        self.refreshControl?.beginRefreshing()
        self.tableView.contentOffset = offset
    }
}

Swift 2.3:

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

    if self.refreshControl?.refreshing == true {
        let offset = self.tableView.contentOffset

        self.refreshControl?.endRefreshing()
        self.refreshControl?.beginRefreshing()
        self.tableView.contentOffset = offset
    }
}

In iOS 11 this approach works much better than the others

class AMRefreshControl: UIRefreshControl {

    override func didMoveToWindow() {
        super.didMoveToWindow()

        if window != nil && isRefreshing, let scrollView = superview as? UIScrollView {
            let offset = scrollView.contentOffset
            UIView.performWithoutAnimation {
                endRefreshing()
            }
            beginRefreshing()
            scrollView.contentOffset = offset
        }
    }
}

This still is an issue in iOS11. The solution needs to be modified a bit though, otherwise the refresh control will spin too fast

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if(self.refreshControl.isRefreshing) {
        CGPoint offset = self.tableView.contentOffset;
        [self.refreshControl endRefreshing];

        // Delay the restart
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self.refreshControl beginRefreshing];
            self.tableView.contentOffset = offset;
        });
    }
}

I am Xamarin developer and got this issue on ListView + TabbedPage, which uses UITableView + UIRefreshControl on iOS. Only the first tabbed page has a good spinning AcitivityIndicator (Refresh Control) but the control is frozen on other tabbed pages.

I start to think about why iOS has had this 'bug' for 10 years? The root cause of this issue is iOS doesn't allow invisible animation Refresh Control in the background otherwise it slows down the device performance for no benefit.

So I got the correct way to fix it: only display Refresh Control when the page is visible and hide it as soon as the page is hidden.

in Xamarin:

protected override void OnAppearing()
{
    base.OnAppearing();
    MyActivityIndicator.IsVisible = IsBusy;
}

protected override void OnDisappearing()
{
    base.OnDisappearing();
    MyActivityIndicator.IsRefresh = false;
}

public bool IsBusy
{
  ...
    set
    {
        ...
        if(IsVisible) MyActivityIndicator.IsRefresh = value;
    }
}

I added the MyActivityIndicator in ListView.FooterTemplate to indicate loading pages and set ListView.IsRefresh to false as soon as receiving refresh command and clear ListView items. should add similar code for ListView.IsRefresh in above code example if you need to display the refresh control above list data.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top