没有UITableViewController的UIRefreshControl

只是好奇,因为它似乎不可能,但是有没有偷偷摸摸的方式来利用新的iOS 6 UIRefreshControl类而不使用UITableViewController子类?

我经常使用带有UITableView子视图的UIViewController ,并且符合UITableViewDataSourceUITableViewDelegate而不是直接使用UITableViewController

根据DrummerB的启发,我试着简单地将一个UIRefreshControl实例作为子视图添加到我的UITableView 。 而神奇的是,它的作品!

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

这将在您的表视图上添加一个UIRefreshControl ,并按预期方式工作,而不必使用UITableViewController 🙂


编辑:这上面仍然有效,但正如一些人已经指出,以这种方式添加UIRefreshControl时有一个轻微的“口吃”。 解决scheme是实例化一个UITableViewController,然后设置你的UIRefreshControl和UITableView,即:

 UITableViewController *tableViewController = [[UITableViewController alloc] init]; tableViewController.tableView = self.myTableView; self.refreshControl = [[UIRefreshControl alloc] init]; [self.refreshControl addTarget:self action:@selector(getConnections) forControlEvents:UIControlEventValueChanged]; tableViewController.refreshControl = self.refreshControl; 

为了消除由接受的答案引起的口吃,你可以将你的UITableView分配给一个UITableViewController

 _tableViewController = [[UITableViewController alloc]initWithStyle:UITableViewStylePlain]; [self addChildViewController:_tableViewController]; _tableViewController.refreshControl = [UIRefreshControl new]; [_tableViewController.refreshControl addTarget:self action:@selector(loadStream) forControlEvents:UIControlEventValueChanged]; _theTableView = _tableViewController.tableView; 

编辑:

添加没有UITableViewControllerUIRefreshControl没有口吃的方法,并在刷新tableview上的数据后保留漂亮的animation。

 UIRefreshControl *refreshControl = [UIRefreshControl new]; [refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged]; [self.theTableView addSubview:refreshControl]; [self.theTableView sendSubviewToBack:refreshControl]; 

稍后处理刷新的数据时…

 - (void)handleRefresh:(UIRefreshControl *)refreshControl { [self.theTableView reloadData]; [self.theTableView layoutIfNeeded]; [refreshControl endRefreshing]; } 

你会尝试使用你正在使用的ViewController里面的容器视图。 你可以使用专用的tableview定义干净的UITableViewController子类,并将其放置在ViewController中。

那么UIRefreshControl是一个UIView子类,所以你可以自己使用它。 我不确定它是如何呈现自己的。 渲染可以简单地依赖于框架,但也可以依赖于UIScrollView或UITableViewController。

无论哪种方式,这将是一个比优雅的解决scheme更多的黑客。 我build议您查看一个可用的第三方克隆或写你自己的。

ODRefreshControl

在这里输入图像描述

SlimeRefresh

在这里输入图像描述

在tableView重新加载其内容之后,尝试延迟对refreshControl -endRefresh方法的调用,方法是使用NSObject的-performSelector:withObject:afterDelay:或GCD的dispatch_after

我在UIRefreshControl上为此创build了一个类别:

 @implementation UIRefreshControl (Delay) - (void)endRefreshingAfterDelay:(NSTimeInterval)delay { dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [self endRefreshing]; }); } @end 

我testing了它,这也适用于集合视图。 我注意到,只要0.01秒就足够了:

 // My data refresh process here while the refresh control 'isRefreshing' [self.tableView reloadData]; [self.refreshControl endRefreshingAfterDelay:.01]; 

IOS 10 Swift 3.0

这很简单

 import UIKit class ViewControllerA: UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var myTableView: UITableView! override func viewDidLoad() { super.viewDidLoad() myTableView.delegate = self myTableView.dataSource = self if #available(iOS 10.0, *) { let refreshControl = UIRefreshControl() let title = NSLocalizedString("PullToRefresh", comment: "Pull to refresh") refreshControl.attributedTitle = NSAttributedString(string: title) refreshControl.addTarget(self, action: #selector(refreshOptions(sender:)), for: .valueChanged) myTableView.refreshControl = refreshControl } } @objc private func refreshOptions(sender: UIRefreshControl) { // Perform actions to refresh the content // ... // and then dismiss the control sender.endRefreshing() } // MARK: - Table view data source func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 12 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) cell.textLabel?.text = "Cell \(String(indexPath.row))" return cell } } 

在这里输入图像描述

如果你想了解iOS 10 UIRefreshControl阅读这里

添加刷新控件作为子视图会在节标题上方创build一个空白空间。

相反,我embeddedUITableViewController到我的UIViewController,然后改变我的tableView属性指向embedded式的,中提琴! 最小的代码更改。 🙂

脚步:

  1. 在Storyboard中创build一个新的UITableViewController并将其embedded到原始的UIViewController中
  2. replace@IBOutlet weak var tableView: UITableView! 与新embedded的UITableViewController的一个,如下所示

 class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() let tableViewController = self.childViewControllers.first as! UITableViewController tableView = tableViewController.tableView tableView.dataSource = self tableView.delegate = self // Now we can (properly) add the refresh control let refreshControl = UIRefreshControl() refreshControl.addTarget(self, action: "handleRefresh:", forControlEvents: .ValueChanged) tableViewController.refreshControl = refreshControl } ... } 

对于Swift 2.2。

首先使UIRefreshControl()。

 var refreshControl : UIRefreshControl! 

在你的viewDidLoad()方法中添加:

 refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: "Refreshing..") refreshControl.addTarget(self, action: #selector(YourUIViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged) self.tableView.addSubview(refreshControl) 

并使刷新function

 func refresh(refreshControl: UIRefreshControl) { // do something ... // reload tableView self.tableView.reloadData() // End refreshing refreshControl.endRefreshing() } 

这是另一个有点不同的解决scheme。

我不得不使用它,因为我有一些视图层次结构问题:我创build了一些function,需要在视图层次结构中的不同位置传递视图,当使用UITableViewController的tableview b / c tableView是UITableViewController的根视图self.view)而不仅仅是一个普通的视图,它创build了不一致的控制器/视图层次结构,并导致崩溃。

基本上创build你自己的UITableViewController的子类和重载loadView分配self.view一个不同的视图,并重写tableView属性返回一个单独的tableview。

例如:

 @interface MyTableVC : UITableViewController @end @interface MyTableVC () @property (nonatomic, strong) UITableView *separateTableView; @end @implementation MyTableVC - (void)loadView { self.view = [[UIView alloc] initWithFrame:CGRectZero]; } - (UITableView *)tableView { return self.separateTableView; } - (void)setTableView:(UITableView *)tableView { self.separateTableView = tableView; } @end 

当与Keller的解决scheme相结合,这将更加强大,因为tableView现在是一个常规的视图,而不是VC的根视图,并且对更改视图层次结构更加强大。 以这种方式使用它的例子:

 MyTableVC *tableViewController = [[MyTableVC alloc] init]; tableViewController.tableView = self.myTableView; self.refreshControl = [[UIRefreshControl alloc] init]; [self.refreshControl addTarget:self action:@selector(getConnections) forControlEvents:UIControlEventValueChanged]; tableViewController.refreshControl = self.refreshControl; 

还有另一种可能的用途:

由于这种方法的子类从self.tableView分离self.view,所以现在可以使用这个UITableViewController作为更多的常规控制器,并添加其他子视图self.view没有怪异的添加子视图到UITableView,所以可以考虑使他们直接查看控制器的UITableViewController的子类,而不是有UITableViewController子项。

有些事情要注意:

由于我们在不调用super的情况下重写tableView属性,因此可能需要注意某些事项,并在必要时处理。 例如,在我上面的例子中设置tableview不会将tableview添加到self.view,也不会设置您可能想要执行的框架。 另外,在这个实现中,当实例化类时,没有默认的tableView,这也是你可能考虑添加的东西。 我不把它包括在内,因为这是个案,这个解决scheme实际上与凯勒的解决scheme非常吻合。

尝试这个,

上面的解决scheme是好的,但tableView.refreshControl只适用于UITableViewController,直到iOS 9.x和从iOS 10.x开始进入UITableView。

写在Swift 3 –

 let refreshControl = UIRefreshControl() refreshControl.addTarget(self, action: #selector(FeedViewController.loadNewData), for: UIControlEvents.valueChanged) // Fix for the RefreshControl Not appearing in background tableView?.addSubview(refreshControl) tableView.sendSubview(toBack: refreshControl) 

凯勒的第一个build议会导致iOS 7中的一个奇怪的错误,在视图控制器重新出现后,表格的插入增加。 改变第二个答案,使用uitableviewcontroller,为我解决了一些问题。

事实certificate,当你使用UITableView子视图的UIViewController并且符合UITableViewDataSource和UITableViewDelegate时,你可以使用下面的代码:

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