可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Just curious, as it doesn\'t immediately seem possible, but is there a sneaky way to leverage the new iOS 6 UIRefreshControl
class without using a UITableViewController
subclass?
I often use a UIViewController
with a UITableView
subview and conform to UITableViewDataSource
and UITableViewDelegate
rather than using a UITableViewController
outright.
回答1:
On a hunch, and based on DrummerB\'s inspiration, I tried simply adding a UIRefreshControl
instance as a subview to my UITableView
. And it magically just works!
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.myTableView addSubview:refreshControl];
This adds a UIRefreshControl
above your table view and works as expected without having to use a UITableViewController
:)
EDIT: This above still works but as a few have pointed out, there is a slight \"stutter\" when adding the UIRefreshControl in this manner. A solution to that is to instantiate a UITableViewController, and then setting your UIRefreshControl and UITableView to that, i.e.:
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;
回答2:
To eliminate the stutter that is caused by the accepted answer, you can assign your UITableView
to a 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;
EDIT:
A way to add a UIRefreshControl
with no UITableViewController
with no stutter and retain the nice animation after refreshing data on the tableview.
UIRefreshControl *refreshControl = [UIRefreshControl new];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.theTableView addSubview:refreshControl];
[self.theTableView sendSubviewToBack:refreshControl];
Later when handling the refreshed data...
- (void)handleRefresh:(UIRefreshControl *)refreshControl {
[self.theTableView reloadData];
[self.theTableView layoutIfNeeded];
[refreshControl endRefreshing];
}
回答3:
What you would try is use container view inside ViewController you are using. you can define clean UITableViewController subclass with dedicated tableview and place that in the ViewController.
回答4:
Well UIRefreshControl is a UIView subclass, so you can use it on it\'s own. I\'m not sure though how it renders itself. The rendering could simply depend on the frame, but it also could rely on a UIScrollView or the UITableViewController.
Either way, it\'s going to be more of a hack than an elegant solution. I recommend you look into one of the available 3rd party clones or write your own.
ODRefreshControl
SlimeRefresh
回答5:
Try delaying the call to the refreshControl -endRefresh
method by a fraction of a second after the tableView reloads its contents, either by using NSObject\'s -performSelector:withObject:afterDelay:
or GCD\'s dispatch_after
.
I created a category on UIRefreshControl for this:
@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
I tested it and this also works on Collection Views. I\'ve noticed that a delay as small as
0.01 seconds is enough:
// My data refresh process here while the refresh control \'isRefreshing\'
[self.tableView reloadData];
[self.refreshControl endRefreshingAfterDelay:.01];
回答6:
IOS 10 Swift 3.0
it\'s simple
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
}
}
If you want to learn about iOS 10 UIRefreshControl read here.
回答7:
Adding the refresh control as a subview creates an empty space above section headers.
Instead, I embedded a UITableViewController into my UIViewController, then changed my tableView
property to point towards the embedded one, and viola! Minimal code changes. :-)
Steps:
- Create a new UITableViewController in Storyboard and embed it into your original UIViewController
- Replace
@IBOutlet weak var tableView: UITableView!
with the one from the newly embedded UITableViewController, as shown below
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
}
...
}
回答8:
For Swift 2.2 .
First make UIRefreshControl() .
var refreshControl : UIRefreshControl!
In your viewDidLoad() method add:
refreshControl = UIRefreshControl()
refreshControl.attributedTitle = NSAttributedString(string: \"Refreshing..\")
refreshControl.addTarget(self, action: #selector(YourUIViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refreshControl)
And make refresh function
func refresh(refreshControl: UIRefreshControl) {
// do something ...
// reload tableView
self.tableView.reloadData()
// End refreshing
refreshControl.endRefreshing()
}
回答9:
Here\'s another solution which is a little different.
I had to use it because of some view hierarchy issues I had: I was creating some functionality that required passing views around to different places in the view hierarchy, which broken when using a UITableViewController\'s tableview b/c the tableView is the UITableViewController\'s root view (self.view) and not just a regular view, it created inconsistent controller / view hierarchies and caused a crash.
Basically create your own subclass of UITableViewController and override loadView to assign self.view a different view, and override the tableView property to return a separate tableview.
for example:
@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
When combined with Keller\'s solution this will more robust in the sense that the tableView is now a regular view, not a VC\'s root view, and be more robust against changing view hierarchies. Example of using it this way:
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;
There is another possible use for this:
Since subclassing this way separates self.view from self.tableView, it\'s possible now to use this UITableViewController as more of a regular controller, and add other subviews to self.view without the oddities of adding subviews to UITableView, so one may considering making their view controllers directly a subclass of UITableViewController instead of having UITableViewController children.
Some things to watch out for:
Since we\'re overriding the tableView property without calling super, there may be some things to watch out for and should handle where necessary. For example, setting the tableview in my above example will not add the tableview to self.view and not set the frame which you may want to do. Also, in this implementation there is no default tableView given to you when the class is instantiated, which is also something you may consider adding. I don\'t include it here because that is case by case, and this solution actually fits well with Keller\'s solution.
回答10:
Try this,
The Above solutions are fine but tableView.refreshControl is available for UITableViewController only, till iOS 9.x and comes in UITableView from iOS 10.x onwards.
Written in 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)
回答11:
Keller\'s first suggestion causes a strange bug in iOS 7 where the inset of the table is increased after the view controller reappears. Changing to the second answer, using the uitableviewcontroller, fixed things for me.
回答12:
It turns out you can use the following when you use a UIViewController with a UITableView subview and conform to UITableViewDataSource and UITableViewDelegate:
self.refreshControl = [[UIRefreshControl alloc]init];
[self.refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];