UIRefreshControl - beginRefreshing не работает, когда UITableViewController находится внутри UINavigationController
Я установил UIRefreshControl в свой UITableViewController (который находится внутри UINavigationController), и он работает так, как ожидалось (т.е. выталкивает правильное событие). Однако, если я программно вызывать метод экземпляра beginRefreshing
в элементе управления обновлением, например:
[self.refreshControl beginRefreshing];
Ничего не происходит. Он должен анимировать вниз и показать прядильщик. Метод endRefreshing
работает правильно, когда я вызываю это после обновления.
Я взломал базовый проект прототипа с таким поведением, и он работает правильно, когда мой UITableViewController добавлен непосредственно в контроллер представления корневых приложений делегата, например:
self.viewController = tableViewController;
self.window.rootViewController = self.viewController;
Но если я сначала добавлю tableViewController
в UINavigationController, добавьте контроллер навигации в качестве rootViewController
, метод beginRefreshing
больше не работает. Например.
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController];
self.viewController = navController;
self.window.rootViewController = self.viewController;
Я чувствую, что это связано с тем, что вложенные иерархии представлений в контроллере навигации не играют хорошо с контролем переподготовки - любые предложения?
Спасибо
Ответы
Ответ 1
Похоже, что если вы начнете обновлять программно, вам придется прокрутить табличное представление, скажем, путем изменения contentoffset
[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];
Я думаю, причина этого в том, что может быть нежелательно переходить к элементу управления обновлением, когда пользователь находится в середине/внизу табличного представления?
Версия Swift 2.2 от @muhasturk
self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true)
В двух словах, чтобы сохранить этот портативный добавить это расширение
UIRefreshControl + ProgramaticallyBeginRefresh.swift
extension UIRefreshControl {
func programaticallyBeginRefreshing(in tableView: UITableView) {
beginRefreshing()
let offsetPoint = CGPoint.init(x: 0, y: -frame.size.height)
tableView.setContentOffset(offsetPoint, animated: true)
}
}
Ответ 2
UITableViewController имеет свойство autoAdjustsScrollViewInsets после iOS 7. В представлении таблицы может уже быть contentOffset, обычно (0, -64).
Итак, правильный способ показать refreshControl после программирования начать обновление - это добавить refreshControl height в существующее contentOffset.
[self.refreshControl beginRefreshing];
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];
Ответ 3
Здесь быстрое расширение с использованием стратегий, описанных выше.
extension UIRefreshControl {
func beginRefreshingManually() {
if let scrollView = superview as? UIScrollView {
scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: true)
}
beginRefreshing()
}
}
Ответ 4
Ни один из других ответов не работал у меня. Они заставили бы spinner показать и вращаться, но само обновление никогда не произойдет. Это работает:
id target = self;
SEL selector = @selector(example);
// Assuming at some point prior to triggering the refresh, you call the following line:
[self.refreshControl addTarget:target action:selector forControlEvents:UIControlEventValueChanged];
// This line makes the spinner start spinning
[self.refreshControl beginRefreshing];
// This line makes the spinner visible by pushing the table view/collection view down
[self.tableView setContentOffset:CGPointMake(0, -1.0f * self.refreshControl.frame.size.height) animated:YES];
// This line is what actually triggers the refresh action/selector
[self.refreshControl sendActionsForControlEvents:UIControlEventValueChanged];
Обратите внимание, что в этом примере используется представление таблицы, но оно также может быть просмотром коллекции.
Ответ 5
Уже упомянутый подход:
[self.refreshControl beginRefreshing];
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];
сделал бы прядильщик видимым. Но он не оживился. Единственное, что я изменил, это порядок этих двух методов, и все сработало:
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];
[self.refreshControl beginRefreshing];
Ответ 6
См. также этот вопрос
UIRefreshControl не показывает колючие при вызове beginRefreshing и contentOffset 0
Мне кажется, что это ошибка, потому что это происходит только тогда, когда свойство contentOffset таблицыView равно 0
Я исправил это с помощью следующего кода (метод для UITableViewController):
- (void)beginRefreshingTableView {
[self.refreshControl beginRefreshing];
if (self.tableView.contentOffset.y == 0) {
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
} completion:^(BOOL finished){
}];
}
}
Ответ 7
Для Swift 4/4.1
Смесь существующих ответов сделает всю работу за меня:
refreshControl.beginRefreshing()
tableView.setContentOffset(CGPoint(x: 0, y: tableView.contentOffset.y - (refreshControl.frame.size.height)), animated: true)
Надеюсь это поможет!
Ответ 8
Он отлично работает для меня:
Swift 3:
self.tableView.setContentOffset(CGPoint(x: 0, y: -self.refreshControl!.frame.size.height - self.topLayoutGuide.length), animated: true)
Ответ 9
Вот расширение Swift 3, в котором отображается прядильщик, а также его анимация.
import UIKit
extension UIRefreshControl {
func beginRefreshingWithAnimation() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
if let scrollView = self.superview as? UIScrollView {
scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - self.frame.height), animated: true)
}
self.beginRefreshing()
}
}
}
Ответ 10
В дополнение к решению @Dymitry Shevchenko.
Я нашел приятное обходное решение этой проблемы. Вы можете создать расширение до UIRefreshControl
, которое перезаписывает метод:
// Adds code forgotten by Apple, that changes content offset of parent scroll view (table view).
- (void)beginRefreshing
{
[super beginRefreshing];
if ([self.superview isKindOfClass:[UIScrollView class]]) {
UIScrollView *view = (UIScrollView *)self.superview;
[view setContentOffset:CGPointMake(0, view.contentOffset.y - self.frame.size.height) animated:YES];
}
}
Вы можете использовать новый класс, установив собственный класс в Identity Inspector для управления обновлением в Interface Builder.
Ответ 11
Форт Свифт 2.2 +
self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true)
Ответ 12
Если вы используете Rxswift для Swift 3.1, можете использовать ниже:
func manualRefresh() {
if let refreshControl = self.tableView.refreshControl {
self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.height), animated: true)
self.tableView.refreshControl?.beginRefreshing()
self.tableView.refreshControl?.sendActions(for: .valueChanged)
}
}
Эта работа для быстрого 3.1, iOS 10.
Ответ 13
Я использую ту же технику, что и зрительный знак "данные обновляется". Результат пользователя приносит приложение из фона, а фиды/списки будут обновляться с помощью пользовательского интерфейса, например, пользователи затягивают таблицы, чтобы обновить себя. Моя версия содержит 3 вещи
1) Кто отправляет "просыпаться"
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationHaveToResetAllPages object:nil];
}
2) Наблюдатель в UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(forceUpdateData) name:kNotificationHaveToWakeUp:nil];
}
3) Протокол
#pragma mark - ForcedDataUpdateProtocol
- (void)forceUpdateData {
self.tableView.contentOffset = CGPointZero;
if (self.refreshControl) {
[self.refreshControl beginRefreshing];
[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];
[self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:1];
}
}
![result]()
Ответ 14
Для Swift 5 для меня не хватало только вызова refreshControl.sendActions(.valueChanged)
. Я сделал расширение, чтобы сделать его чище.
extension UIRefreshControl {
func beginRefreshingManually() {
if let scrollView = superview as? UIScrollView {
scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: false)
}
beginRefreshing()
sendActions(for: .valueChanged)
}
}