UIRfreshControl — как сделать так, чтобы действие обновления происходило после того, как касание отпущено?

Давний слушатель, первый раз вызывающий здесь при переполнении стека. Быть нежным.

Я реализую UIRfreshControl в UITableView для обновления данных таблицы. В других реализациях обновления по запросу процесс обновления не начинается до тех пор, пока пользователь не поднимет палец, находясь на расстоянии обновления по запросу. UIRfreshControl сразу не кажется, что у него есть эта настройка.

Мой код инициализации UIRfreshControl:

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

Мой код обновления: довольно простой:

-(void)refresh:(id)sender {
(... refresh code ...)
[sender endRefreshing];
}

Как я могу отложить функцию обновления: до тех пор, пока пользователь не уберет палец с экрана?


person outphase    schedule 23.03.2013    source источник


Ответы (3)


Я тоже застрял с той же проблемой. Я не думаю, что мой подход очень хорош, но похоже, что он работает.

  1. Инициализировать UIRefreshControl

    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
    self.refreshControl = refreshControl;
    
  2. Проверить состояние UIRefreshControl, когда пользователь закончит перетаскивание таблицы (UITableViewDelegate соответствует UIScrollViewDelegate)

    - (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView
    {    
        if( self.refreshControl.isRefreshing )
            [self refresh];
    }
    
  3. Обновить таблицу

    - (void)refresh
    {
        [self.refreshControl endRefreshing];
    
        // TODO: Update here your items
    
        [self.tableView reloadData];
    }
    

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

person Ned    schedule 23.03.2013
comment
Это решение работает, если пользователь медленно выполняет перетаскивание. Если это почти как щелчок, загрузочное колесо будет работать, но функция refresh: не будет вызываться до тех пор, пока таблица не будет снова перемещена. edit: я изменил функцию на scrollViewDidEndDecelerating: и теперь она работает нормально. Спасибо! - person outphase; 24.03.2013
comment
Да, вы совершенно правы! Теперь он работает намного лучше, спасибо за исправление моего кода!) - person Ned; 24.03.2013
comment
С этим есть небольшая проблема. Если вы потянете вид таблицы вниз достаточно, чтобы обновить, держите палец внизу, вернитесь к тому месту, где счетчик виден примерно наполовину, затем отпустите ... он покажет, что счетчик вращается, и ничего не произойдет. - person Cameron Askew; 16.06.2014
comment
@CameronAskew, это поведение можно исправить, вызвав тот же код, что и в scrollViewDidEndDecelerating, также внутри метода scrollViewDidEndDragging. Но в этом случае нам также придется закрыть управление обновлением, вызвав setContentOffset(CGPoint.zero, animated: true) нашего UIScrollView или UITableView. - person Andrei K.; 07.12.2017

UIRefreshControl уже имеет приспособления для старта в "нужное" время. Правильным поведением элемента управления «вытягивание для обновления» является запуск обновления после того, как пользователь пересек некоторый «достаточно далеко» порог, а не когда пользователь отпустил перетаскивание.

Для этого вам нужно изменить метод -refresh:, чтобы он проверял, когда элемент управления перешел в состояние refreshing:

-(void)refresh:(id)sender {
    UIRefreshControl *refreshControl = (UIRefreshControl *)sender;
    if(refreshControl.refreshing) {
        (... refresh code ...)
    }
}

Обратите внимание, что любой метод, который вы вызываете для своего (... refresh code ...), должен быть асинхронным, чтобы ваш пользовательский интерфейс не зависал. Вы должны перейти в основную очередь и вызвать -endRefreshing в конце вашего блока (... refresh code ...), а не в конце -refresh::

- (void)refresh:(id)sender {
    __weak UIRefreshControl *refreshControl = (UIRefreshControl *)sender;
    if(refreshControl.refreshing) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            /* (... refresh code ...) */
            dispatch_sync(dispatch_get_main_queue(), ^{
                [refreshControl endRefreshing];
                //reload the table here, too
            });
        });
    }
}

Изменение управляющего события на UIControlEventTouchUpInside не будет работать, потому что UIRefreshControl не является компонентом пользовательского интерфейса, предназначенным для прямого взаимодействия. Пользователь никогда не прикоснется к UIRefreshControl, поэтому никакое событие UIControlEventTouchUpInside не может быть инициировано.

person Community    schedule 23.03.2013
comment
это не работает. метод обновления вызывается только один раз, прежде чем пользователь поднимет палец (проверено с ios 10.2) - person user1105951; 12.01.2017
comment
Поведение UIRefreshControl изменилось за последние 5 лет. Обычная реализация (то, что было описано в вопросе) теперь ведет себя корректно, если работа по обновлению не блокирует основной поток. Это поведение соответствует элементам управления обновлением системы (например, в Mail). Начальное обновление в -scrollViewDidEndDecelerating: не выполняется. - person ; 25.11.2018

Запланировать обновление только при поднятии пальца можно с помощью NSRunLoop. Вызовите -(void)performInModes:(NSArray<NSRunLoopMode> *)modes block:(void (^)(void))block; с NSRunLoopDefaultMode в массиве.

Пока касание все еще удерживается, режим цикла выполнения — UITrackingRunLoopMode, он вернется к умолчанию только после отрыва.

person DrMickeyLauer    schedule 12.10.2018