Pull to Refresh Uitableview Without Uitableviewcontroller

Pull to refresh UITableView without UITableViewController

Add a refresh control directly to a UITableView without using a UITableViewController:

override func viewDidLoad() {
super.viewDidLoad()
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refresh(_:)), for: .valueChanged)

if #available(iOS 10.0, *) {
tableView.refreshControl = refreshControl
} else {
tableView.backgroundView = refreshControl
}
}

@objc func refresh(_ refreshControl: UIRefreshControl) {
// Do your job, when done:
refreshControl.endRefreshing()
}

How to pull to refresh without tableView?

There doesn't appear to be anything wrong with your approach.

Here is a complete example -- it adds a "full view" scrollView, with a 200-pt tall red subview (so we can see the effect).

When you drag down, you should see the UIRefreshControl "spinner" appear. Drag down far enough, and it will call the updateView() func. Since we don't have your SyncScheduler code, I added a 2-second async delay to simulate the process:

final class CategoryBreakdownViewController: UIViewController {

private let scrollView = UIScrollView()
var refreshControl = UIRefreshControl()

override func viewDidLoad() {
super.viewDidLoad()

scrollView.backgroundColor = .systemTeal
scrollView.translatesAutoresizingMaskIntoConstraints = false

let testView = UIView()
testView.backgroundColor = .red
testView.translatesAutoresizingMaskIntoConstraints = false

scrollView.addSubview(testView)
view.addSubview(scrollView)

let contentGuide = scrollView.contentLayoutGuide
let frameGuide = scrollView.frameLayoutGuide

NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),

testView.topAnchor.constraint(equalTo: contentGuide.topAnchor, constant: 20.0),
testView.leadingAnchor.constraint(equalTo: contentGuide.leadingAnchor, constant: 20.0),
testView.trailingAnchor.constraint(equalTo: contentGuide.trailingAnchor, constant: -20.0),
testView.bottomAnchor.constraint(equalTo: contentGuide.bottomAnchor, constant: -20.0),

testView.widthAnchor.constraint(equalTo: frameGuide.widthAnchor, constant: -40.0),
testView.heightAnchor.constraint(equalToConstant: 200.0),
])

setupRefreshControl()
}

private func setupRefreshControl() {
scrollView.alwaysBounceVertical = true
scrollView.bounces = true
refreshControl.addTarget(self, action: #selector(updateView), for: .valueChanged)
self.scrollView.addSubview(refreshControl)
}

@objc func updateView() {

// simulate a background process that takes 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
self.refreshControl.endRefreshing()
})

// SyncScheduler.syncImmediately(
// success: {
// self.refreshControl.endRefreshing()
// },
// failure: { [weak self] errorMessage in
// self?.present(message: errorMessage, style: .error)
// self?.refreshControl.endRefreshing()
// }
// )

}
}

refreshControl with programatic UITableView without UITableViewController

You can do this in the following way:

//1: Add an instance variable to your ViewController.

let refreshControl = UIRefreshControl()

//2: In viewDidLoad() set up your refresh control

refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)

//3: And (still in the viewDidLoad()) add it as a subview to the tableView (UITableView)

tableView.addSubview(refreshControl)

//4: Finally, in your refresh() function: do not forget to end the refreshing of this control.

refreshControl.endRefreshing()

// Be aware, this (end of refreshing) must be done on the main queue! - if you are not there. In such case you might use something like:

dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl.endRefreshing()
}

Remarks to your code:

  1. You do not have to use semicolons anymore :-).

  2. Refresh control and the refresh control selector can not have the same name (i.e. action: "refresh").

  3. There is no "self.refreshControl = refresh;".

UIRefreshControl without UITableViewController

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;

How to activate refresh control without pulling down (Swift)

The solution was quite simple:

refreshControl.beginRefreshing()

https://developer.apple.com/documentation/uikit/uirefreshcontrol/1624842-beginrefreshing

Obj-C - Add activity indicator to pull down to refresh?

This is what ended up working!

ViewController.h

@property (nonatomic, strong) UIRefreshControl *refreshControl;

ViewController.m

 - (void)viewDidLoad {
[super viewDidLoad];

self.refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl.attributedTitle = [[NSAttributedString alloc]initWithString:@"Pull To Refresh"];
[self.refreshControl addTarget:self action:@selector(refreshData) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:self.refreshControl];

}

-(void)refreshData
{


// Wait 1 sec before ending refreshing for testing
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[self.refreshControl endRefreshing];
});
}

How to use pull to refresh in Swift?

Pull to refresh is built in iOS. You could do this in swift like

let refreshControl = UIRefreshControl()

override func viewDidLoad() {
super.viewDidLoad()

refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: #selector(self.refresh(_:)), for: .valueChanged)
tableView.addSubview(refreshControl) // not required when using UITableViewController
}

@objc func refresh(_ sender: AnyObject) {
// Code to refresh table view
}

At some point you could end refreshing.

refreshControl.endRefreshing()


Related Topics



Leave a reply



Submit