UIRefreshControl застрял после переключения вкладок в UITabBarController
У меня есть UITableViewController в качестве контроллера корневого представления в UINavigationController, который, в свою очередь, является одним из контроллеров представления в UITabBarController. Все подключены к раскадровке.
Я также настроил UIRefreshControl для своей таблицы в Storyboard, и обычно это выглядит так, как нужно, когда вытягиваете:
![Normal UIRefreshControl]()
Однако, если я переключаюсь между моими другими вкладками один или два раза, это выглядит так:
![Buggy UIRefreshControl]()
Это не крутит или что-то еще, просто застрял "полный", и он остается таким, пока я полностью не вытащу и не запустим обновление.
Любые идеи или предложения ценят.
Ответы
Ответ 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, то вращатель будет анимироваться и удаляться в течение доли секунды, в любом из случаев проблема будет решена, но, с точки зрения пользователей, вращатель не должен быть видимым, поэтому он Лучше разместить его в поле зрения исчезнуть.