Подтвердить что ты не робот

UIRefreshControl застрял после переключения вкладок в UITabBarController

У меня есть UITableViewController в качестве контроллера корневого представления в UINavigationController, который, в свою очередь, является одним из контроллеров представления в UITabBarController. Все подключены к раскадровке.

Я также настроил UIRefreshControl для своей таблицы в Storyboard, и обычно это выглядит так, как нужно, когда вытягиваете:

Normal UIRefreshControl

Однако, если я переключаюсь между моими другими вкладками один или два раза, это выглядит так:

Buggy UIRefreshControl

Это не крутит или что-то еще, просто застрял "полный", и он остается таким, пока я полностью не вытащу и не запустим обновление.

Любые идеи или предложения ценят.

4b9b3361

Ответ 1

Я знаю, что это невероятно поздно, но я думаю лучше поздно, чем никогда.

К сожалению, ни один из этих ответов не работал у меня. Единственное, что сработало, это ужасный кусок кода в viewWillAppear:

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

В основном я воссоздаю UIRefreshControl каждый раз, когда будет отображаться представление. Он работает, хотя и дает следующее предупреждение:

Попытка изменить элемент управления обновлением, пока он не находится в режиме ожидания сильно обескуражен и, вероятно, не будет работать должным образом.

Я искренне удивлен, что это все еще проблема (все еще видя это в iOS 9 сейчас). Надеюсь, это может быть полезно для некоторых других людей.

Ответ 2

user2009606 был почти прав, я исправил его, позвонив

[refreshControl endRefreshing];

Вкл

viewWillAppear:

Теперь refreshControl ведет себя корректно после переключения вкладок, независимо от его состояния.

Ответ 3

Подводя итог и предоставим полное решение.

Проблема:

Если UIRefreshControl анимируется во время перехода на экран, он останется видимым, но не будет оживлять. Видео https://vid.me/Bkb7

Кроме того, если для обновления анимации был запущен, но не завершен, а затем был выполнен переход, UIRefreshControl будет скрыт, но застрял. Видео https://vid.me/Bkb7

Решение:

Запустите анимацию UIRefreshControl на viewWillAppear и запустите ее на viewDidDisappear. Сохраните состояние процесса обновления, чтобы узнать, когда показывать UIRefreshControl.

Bellow - это все решение, которое также обрабатывает надлежащую анимацию и простое растягивание для обновления анимации.

Добавить в UITableView или подкласс

Инициализация:

 /// 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:

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

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

Обработчик анимации UIRefreshControl:

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

Добавить

table.isRefreshing = true

для начала вызова обновления.

Видео с результатами https://vid.me/LyuI

Ответ 4

Это может помочь вам следующее решение.

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

Ответ 5

Просто вызов endRefreshing в viewWillDisappear: исправил все проблемы для меня.

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

Выполнение того же самого в viewWillAppear: заставило элемент управления обновлением странным образом потянуть таблицу.

Ответ 6

Я только что видел то же самое. То, что я закончил, это endRefreshing on viewWillDisappear и, по крайней мере, устраняет эту проблему. Однако, вернувшись на вкладку, я ожидаю, что она снова начнет вращаться, когда я перезапущу процесс обновления и снова вызову beginRefreshing, но это не так. Это происходит в случае, когда я разворачиваю навигацию, а затем возвращаюсь.

Ответ 7

Самое лучшее исправление в Swift:

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

  //fixes bug with refreshControl freezing while switching tabs
  if tableView.contentOffset.y < 0 {
    tableView.contentOffset = .zero
  }
}

Ответ 8

Пока вращается управление обновлением, если вы представляете какой-то другой контроллер и возвращаетесь до "завершения обновления"; анимация обновления застрянет.

Ни один из приведенных выше ответов не помог мне, и я не хотел устанавливать bool и следовать ему в течение всего жизненного цикла контроллера представления.

Мое решение - добавить приведенный ниже код в конец viewWillAppear.

в городе;

if (self.refreshControl.isRefreshing) {
    [self.refreshControl endRefreshing];
    [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated: true];
    [self.refreshControl beginRefreshing];
}

в Swift;

if self.refreshControl.isRefreshing {
     self.refreshControl.endRefreshing
     self.tableView.setContentOffset(CGPoint(x: 0, y: self.tableView.contentOffset.y-self.refreshControl.frame.size.height), animated: true)
     self.refreshControl.beginRefreshing;
}

Логика есть; всякий раз, когда он ловит элемент управления обновлением, находящийся в состоянии анимации, он останавливает его, не зная, застрял он или нет, и повторно запускает анимацию.

Надеюсь, это поможет.

Ответ 9

У меня есть collectionView, и я установил его contentInset.

Когда вы нажимаете некоторые ViewControllers, затем нажимаете кнопку "домой" и возвращаетесь назад и возвращаетесь назад, UIRefreshControl всегда находится на вершине.

Наконец, я использую этот код, чтобы временно его избежать. (Уродливый, но останавливает его всегда показывает сверху)

- (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];
}

Ответ 10

Мне нужны некоторые моменты и как решение Альберта, но не его стиль.

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

Ответ 11

Надеюсь, я смогу помочь в решении этой проблемы, наконец:

Существует проблема с использованием UITableView с элементом управления Pull-To-Refresh. Это может быть ЛЕГКО разрешено, добавив UITableViewController.

UITableViewController *tableController = [[UITableViewController alloc] init];
    tableController.automaticallyAdjustsScrollViewInsets = NO;
    [tableController willMoveToParentViewController:self];
    [self addChildViewController:tableController];
    tableController.tableView = self.containerTableView;
    tableController.refreshControl = self.refreshControl;

Таким образом вы просто переносите UITableView внутри контроллера, для которого [self.refreshControl endRefreshing] будет работать полностью в пределах viewWillAppear или viewWillDisappear. В некоторых случаях вам может потребоваться позвонить в обоих случаях.

Надеюсь, это поможет!:)

Ответ 12

Я не мог получить вызов endRefreshing для работы до того, как произошла навигация, поэтому я подошел к проблеме с другого конца и на viewWillAppear. Я проверяю, является ли tableView contentOffset отрицательным числом, возвращая tableView обратно в 0.

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

    if (self.tableView.contentOffset.y < 0)
    {
        [self.tableView setContentOffset:CGPointZero animated:YES];
    }
}

Ответ 13

Ответы в этом question решили мою проблему

в основном останавливается и снова запускает счетчик на viewWillAppear

Ответ 14

Вы можете попробовать

refreshControl.beginRefreshing()
refreshControl.endRefreshing()

в viewWillAppear, и это должно работать.

Ответ 15

Подробнее

  • Версия Xcode 10.3 (10G8), Swift 5

Проблема

  • Переключение между вкладками приведет к зависанию индикатора активности
  • refreshControl.beginRefreshing(); refreshControl.endRefreshing() - отправит еще один запрос/запрос на обновление события

Решение

refreshControl.removeTarget(actionTarget, action: selector, for: .valueChanged)
refreshControl.endRefreshing()
refreshControl.beginRefreshing()
refreshControl.addTarget(actionTarget, action: actionSelector, for: .valueChanged)

Полное решение и образец

Как использовать pull для обновления в Swift?

Ответ 16

Просто добавьте код ниже и он отлично работает при любых условиях.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    guard refreshControl.isRefreshing else { return }
    refreshControl.endRefreshing()
    refreshControl.beginRefreshing()
    tableView?.contentOffset = CGPoint(x: 0, y: -(refreshControl.bounds.height))
}

Ответ 17

Несколько раз я столкнулся с одной и той же проблемой, я решил создать для нее библиотеку SwiftPullToRefresh.

Как говорилось ранее, refreshControl нужно остановить на viewDidDisappear(_:) и начать с viewWillAppear(_:).

При программном запуске анимации refreshControl tableView.contentOffset необходимо установить соответствующее значение.

tableView.setContentOffset(CGPoint(x: 0, y: -(refreshControl?.bounds.height ?? 60) - topOffset), animated: true)

var topOffset: CGFloat {
    if let navigationBar = navigationController?.navigationBar, navigationBar.isTranslucent == true {
        return navigationBar.bounds.height + UIApplication.shared.statusBarFrame.height
    } else {
        return 0
    }
}

Ответ 18

Мне удалось решить эту проблему, поместив следующий фрагмент кода в viewWillDisappear

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

Если приведенный выше код помещен в viewWillAppear, то вращатель будет анимироваться и удаляться в течение доли секунды, в любом из случаев проблема будет решена, но, с точки зрения пользователей, вращатель не должен быть видимым, поэтому он Лучше разместить его в поле зрения исчезнуть.