UIRefreshControl – 当UITableViewController位于UINavigationController中时,beginRefreshing不工作

我已经在我的UITableViewController(这是一个UINavigationController内)设置一个UIRefreshControl和它按预期的方式工作(即拉下来触发正确的事件)。 但是,如果我以编程方式调用刷新控件上的beginRefreshing实例方法,如:

 [self.refreshControl beginRefreshing]; 

什么都没发生。 它应该animation下来,并显示微调。 刷新后调用endRefreshing方法时可以正常工作。

我用这种行为掀起了一个基本的原型项目,它正常工作时,我的UITableViewController直接添加到应用程序委托的根视图控制器,例如:

 self.viewController = tableViewController; self.window.rootViewController = self.viewController; 

但是,如果我首先添加tableViewController到一个UINavigationController,然后添加导航控制器作为rootViewControllerbeginRefreshing方法不再起作用。 例如

 UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController]; self.viewController = navController; self.window.rootViewController = self.viewController; 

我的感觉是,这与导航控制器中的嵌套视图层次结构有关,不能很好地进行复习控制 – 任何build议?

谢谢

看来,如果你开始以编程方式刷新,你必须自己滚动表格视图,比如说,通过改变contentoffset

 [self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES]; 

我猜想这是因为当用户在表视图的中间/底部滚动到刷新控制可能是不可取的?

由@muhasturk Swift 2.2版本

 self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true) 

UITableViewController在iOS 7后自动调用ScrollViewInsets属性。表视图可能已经有contentOffset,通常为(0,-64)。

因此,编程开始刷新后显示refreshControl的正确方法是将refreshControl的高度添加到现有的contentOffset。

  [self.refreshControl beginRefreshing]; [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES]; 

这是一个使用上述策略的Swift扩展。

 extension UIRefreshControl { func beginRefreshingManually() { if let scrollView = superview as? UIScrollView { scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: true) } beginRefreshing() } } 

没有其他答案为我工作。 他们会导致微调显示和旋转,但刷新行动本身不会发生。 这工作:

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

注意,这个例子使用了一个表格视图,但它也可以是一个集合视图。

已经提到的方法:

 [self.refreshControl beginRefreshing]; [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES]; 

会让纺纱工看得见 但它不会animation。 我改变的一件事是这两种方法的顺序,一切都奏效了:

 [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES]; [self.refreshControl beginRefreshing]; 

另见这个问题

调用beginRefreshing和contentOffset为0时,UIRefreshControl不显示棘手

它看起来像一个bug,因为它只发生在tableView的contentOffset属性为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){ }]; } } 

这对我来说是完美的:

Swift 3:

 self.tableView.setContentOffset(CGPoint(x: 0, y: -self.refreshControl!.frame.size.height - self.topLayoutGuide.length), animated: true) 

除了@Dymitry舍甫琴科的解决scheme。

我发现这个问题很好的解决方法。 您可以创build扩展到覆盖方法的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中为界面构build中的刷新控制设置自定义类来使用新类。

斯威夫特堡2.2+

  self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true) 

如果您使用Rxswift为快速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) } } 

这个工作适用于swift 3.1,iOS 10。

我使用相同的技术来显示用户“数据是更新”的可视标志。 结果用户从后台带来的应用程序和饲料/列表将更新与用户界面像用户拉桌子刷新自己。 我的版本包含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]; } } 

结果

这里是Swift 3的扩展,它显示了微调以及animation。

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