📜 ⬆️ ⬇️

We implement pull to refresh and infinite scrolling on Swift

Let's take the article as a basis. Meet Swift! where it is shown how to make a simple application in Swift, and add there such well-known and useful things like pull to refresh and infinite scrolling using the built-in language features. To make it even more interesting, add a little asynchrony, otherwise the application will freeze each time during the update.



Training


We take the above example as a basis, so we will simply supplement it. To begin with, we add 2 variables to the controller class, which will be responsible for the number of cells and for the text displayed in the cells.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { var countRow = 20 var text = "Habrapost" 

And we modify the cell generation code using these variables.
  func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { return countRow } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestSwiftCell") cell.text = "\(text) \(indexPath.row)" cell.detailTextLabel.text = "Hi, \(indexPath.row)" cell.detailTextLabel.textColor = UIColor.purpleColor() return cell } 

Now we will bind the TableView to the controller so that we can perform the necessary manipulations on it. In the interface builder, select the TableView, press cmd + alt + enter and right-click in the appeared window


We drive in the name by which we will apply

')
We will also add the View component to the TableView, on which we place 2 elements in order to get the following


This View is needed in order to display a notification that an update is in progress, and we need it to be visible only when new data is being loaded (for this we will use the tableFooterView.hidden property), therefore we need to hide it at the beginning, and show only later. You will also need to manually start the animation UIActivityIndicatorView, for this, similarly as above, add a binding




For the preliminary preparation of these actions will be enough.

Pull to refresh


Now you can go directly to the implementation of pull to refresh. In the controller class, add a new variable of the special class UIRefreshControl
  var refreshControl:UIRefreshControl! 

In viewDidLoad, add the code that initializes this variable and binds it to the tableView.
  override func viewDidLoad() { super.viewDidLoad() refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: " ...") refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged) tableView.addSubview(refreshControl) } 

Now we need to define the refresh function, which will be called every time during the pull-to-refresh action. To make the update happen in asynchronous mode, we use the following scheme (I will not go into the description of the details, it's not difficult to figure out the code yourself)
  func refresh(sender:AnyObject) { refreshBegin("Refresh", refreshEnd: {(x:Int) -> () in self.tableView.reloadData() self.refreshControl.endRefreshing() }) } func refreshBegin(newtext:String, refreshEnd:(Int) -> ()) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { println("refreshing") self.text = newtext sleep(2) dispatch_async(dispatch_get_main_queue()) { refreshEnd(0) } } } 

As a result, we get


UPD: If you use UITableViewController (and it is better to use it in this and similar cases), then the code will be even easier. UITableViewController already has tableView and refreshControl properties, so you don’t need to bind the UITableView manually and you don’t need to declare refreshControl in the class. Just write the following code in viewDidLoad and everything will work

  override func viewDidLoad() { super.viewDidLoad() refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: " ...") refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged) } 


Infinite scrolling


With endless scrolling a bit more difficult, but not by much. We will add a new variable loadMoreStatus to the controller class, which will be responsible for protecting it from re-updating if it is already running.
  var loadMoreStatus = false 

In viewDidLoad we will add a code that will initially hide the View with information about the loading of new data
  override func viewDidLoad() { super.viewDidLoad() refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: " ...") refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged) tableView.addSubview(refreshControl) self.tableView.tableFooterView.hidden = true } 

Add the definition of the special function scrollViewDidScroll, which is called every time any scrolling occurs. If we reach the end of the list, the loadMore function is called, which implements the asynchronous loading of new data.
  func scrollViewDidScroll(scrollView: UIScrollView!) { let currentOffset = scrollView.contentOffset.y let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height let deltaOffset = maximumOffset - currentOffset if deltaOffset <= 0 { loadMore() } } func loadMore() { if ( !loadMoreStatus ) { self.loadMoreStatus = true self.activityIndicator.startAnimating() self.tableView.tableFooterView.hidden = false loadMoreBegin("Load more", loadMoreEnd: {(x:Int) -> () in self.tableView.reloadData() self.loadMoreStatus = false self.activityIndicator.stopAnimating() self.tableView.tableFooterView.hidden = true }) } } func loadMoreBegin(newtext:String, loadMoreEnd:(Int) -> ()) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { println("loadmore") self.text = newtext self.countRow += 20 sleep(2) dispatch_async(dispatch_get_main_queue()) { loadMoreEnd(0) } } } 

As a result, everything works, the application does not freeze, and the data is added successfully


In this simple way, you can implement pull to refresh and infinite scrolling, and of course, because of the asynchronous update, you can, for example, make JSON requests to the server in a simple synchronous way and this does not interfere with the operation of the application.

Source: https://habr.com/ru/post/228881/


All Articles