UIRefreshControl没有UITableViewController

只是好奇,因为这似乎不可能立即实现,但是否有一种偷偷摸摸的方法来利用新的iOS 6 UIRefreshControl类而不使用UITableViewController子类?

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

83796 次浏览

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

无论哪种方式,它都将是一种hack而不是优雅的解决方案。我建议你找一个第三方的克隆版本,或者自己写一个。

ODRefreshControl

enter image description here

SlimeRefresh

enter image description here

根据一种直觉,基于DrummerB的灵感,我尝试简单地将UIRefreshControl实例作为子视图添加到我的UITableView中。它神奇地工作了!

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

这将在你的表视图上面添加一个UIRefreshControl,并且无需使用UITableViewController就可以正常工作:)


编辑:上面的方法仍然有效,但正如一些人指出的那样,当以这种方式添加UIRefreshControl时,会有轻微的“口吃”。一个解决方案是实例化一个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;

你要尝试的是在ViewController中使用容器视图。你可以用专用的tableview定义干净的UITableViewController子类并把它放在ViewController中。

为了消除由接受的答案引起的口吃,你可以将你的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;

编辑:

一种添加UIRefreshControl的方法,没有UITableViewController,没有口吃,并在刷新表视图上的数据后保留漂亮的动画。

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

尝试在tableView重载其内容后,通过使用NSObject的-performSelector:withObject:afterDelay:或GCD的dispatch_after,将refreshControl -endRefresh方法的调用延迟几分之一秒。

我在UIRefreshControl上创建了一个类别:

@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
我测试了它,这也适用于集合视图。我注意到,一个小到 0.01秒就足够了:

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

事实证明,当你使用带有UITableView子视图的UIViewController并遵循UITableViewDataSource和UITableViewDelegate时,你可以使用以下方法:

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

Keller的第一个建议在iOS 7中导致了一个奇怪的错误,即在视图控制器重新出现后,表的插入增加了。换到第二个答案,使用uitableviewcontroller,为我解决了问题。

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

我不得不使用它,因为我有一些视图层次结构问题:我正在创建一些功能,需要将视图传递到视图层次结构中的不同地方,当使用UITableViewController的tableview b/c时,tableview是UITableViewController的根视图(self.view),而不仅仅是常规视图,它创建了不一致的控制器/视图层次结构,并导致崩溃。

基本上创建你自己的UITableViewController的子类并重写loadView来赋值self。查看一个不同的视图,并重写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的解决方案相结合时,这将更加健壮,因为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,现在可以使用这个UITableViewController作为更常规的控制器,并添加其他子视图到self。视图,而不需要给UITableView添加子视图,所以你可以考虑让他们的视图控制器直接成为UITableViewController的子类,而不是有UITableViewController的子类。

一些需要注意的事情:

由于我们在不调用super的情况下重写了tableView属性,因此可能需要注意一些事情并在必要时进行处理。例如,在上面的例子中设置tableview不会将tableview添加到self。查看而不是设置你可能想做的框架。此外,在这个实现中,当类实例化时没有默认的tableView,这也是您可以考虑添加的东西。我没有把它包括在这里,因为这是逐案的,这个解实际上很适合凯勒的解。

将刷新控件添加为子视图将在节头上方创建一个空白区域。

相反,我将一个UITableViewController嵌入到我的UIViewController中,然后更改我的tableView属性以指向嵌入的UITableViewController,然后!最小的代码更改。: -)

步骤:

  1. 在Storyboard中创建一个新的UITableViewController并将其嵌入到你原来的UIViewController中
  2. @IBOutlet weak var tableView: UITableView!替换为新嵌入的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)

并创建refresh函数

func refresh(refreshControl: UIRefreshControl) {


// do something ...


// reload tableView
self.tableView.reloadData()


// End refreshing
refreshControl.endRefreshing()
}

试试这个,

上述解决方案是很好的,但tableView。refreshControl只适用于UITableViewController,直到iOS 9。x,来自iOS 10的UITableView。x开始。

写在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)

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
}


}

enter image description here

如果你想了解iOS 10 UIRefreshControl读取here