In this tutorial we will learn to implement custom Pull to Refresh loading indicator using Swift 1.2 in XCode 6.4.

tableView Pull to Refresh

Getting started

Open Xcode and create a new project by choosing the Single View Application template. Choose iPhone under “Devices”. Choose Swift as main language.

Templates

Next, you are presented with the page to set many of the important aspects of your project, particularly your “Product Name” and “Language”, which will be Swift, of course.

Product Name is pretty self-explanatory.  The organization name can be whatever you want, but it probably should the the company or name you are releasing your apps under. We will not have CoreData usage in this tutorial so uncheck the box and Swift is the main language to be used.

When you click next, you will be presented with a save dialog, asking where you want to save your project.  Wherever you save it, a folder will be created with your app’s name, and inside will be the Xcode project, and a folder for each target your app has (which is going to be the app itself, and a test target right now).  You also have the option to create a Git repository for your project either locally or on a server.

After you click the “Create” button, the files for your project are generated and you are probably looking at your AppDelegate.swift file.

Adding custom files

This tutorial requires some custom class files to be imported into our project for the animation & transition to occur. These class files are made freely available to us by entotsu on Github. You can download the class files from here. (Download Link). All credits go to entotsu for this wonderful animation class files. The download link mentioned above provides you with necessary Class files which we will use into our projects in future. Drag the folder & images into our Xcode project once downloaded.

Setting up the Storyboard

For this tutorial we are going to learn how to add UITableView programmatically in swift without a storyboard, so nothing needs to be setup in the storyboard. Let’s dive into the coding part straight away !

Setting up the ViewController code :

Open the ViewController.swift file and add some lines in the viewDidLoad function:

override func viewDidLoad() {
        super.viewDidLoad()
    
        self.view.backgroundColor = UIColor(red:89/255, green: 165/255, blue: 216/255, alpha: 1)
        let bodyView = UIView()
        bodyView.frame = self.view.frame
        bodyView.frame.y += 20 + 44
        self.view.addSubview(bodyView)
        
        let tableView = SampleTableView(frame: self.view.frame, style: UITableViewStyle.Plain)
        
        let tableViewWrapper = PullToBounceWrapper(scrollView: tableView)
        bodyView.addSubview(tableViewWrapper)
        
        tableViewWrapper.didPullToRefresh = {
            NSTimer.schedule(delay: 2) { timer in
                tableViewWrapper.stopLoadingAnimation()
            }
        }
        
        makeHeader()
    }

The code above firstly sets a custom background color with the UIColor RGB function. We then declare the UIView and set it’s frame. This bodyView will consist of our custom tableview, this tableView is a custom object of SampleTableView & set it’s frame as well. Next is the main part of this animation implementation, we wrap the PullToBounceWrapper class to out tableView scrollView and just add the tableView to the bodyView. The makeHeader function adds a custom programatic header to out ViewController and is implemented as shown below.

func makeHeader() {
        let headerView = UIView()
        headerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 64)
        headerView.backgroundColor = UIColor(red:89/255, green: 165/255, blue: 216/255, alpha: 1)
        self.view.addSubview(headerView)
        
        let headerLine = UILabel()
        headerLine.frame = CGRect(x: 0, y: 0, width: 120, height: 100)
        headerLine.center = CGPoint(x: headerView.frame.center.x + 25, y: 20 + 44/2)
        headerLine.textColor = UIColor.whiteColor()
        headerLine.text = "SwiftyOS"
        headerView.addSubview(headerLine)
    }
    
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }

The above code is to be added just below the viewDidLoad function. This adds a headerView with a headerLine having text of SwiftyOS which will be our navigation title. We also add some UI enhancements such as textColor, UIColor schemes, etc. The status bar style is also set to Light Content which makes the color of status bar to white color.

class SampleTableView: UITableView, UITableViewDelegate, UITableViewDataSource {
    
    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        self.delegate = self
        self.dataSource = self
        self.registerClass(SampleCell.self, forCellReuseIdentifier: "SampleCell")
        self.separatorStyle = UITableViewCellSeparatorStyle.None
    }
    
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int  {
        return 30
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("SampleCell", forIndexPath: indexPath) as! SampleCell
        return cell
    }
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 92
    }
}

Now we add & declare the SampleTableView class we used earlier. This class will basically implement all the tableView delegate and dataSource functions. To populate your tableView with data all the implementation goes here. First, we declare the init function for setting thedelegate and dataSource to self ,i.e, viewController. We also use registerClass to register the SampleCell class with the identifier for each cell. Then we implement numberOfRowsInSection, cellForRowAtIndexPath, heightForRowAtIndexPath with no. of rows as 30 and height for each cell to 92. Make sure this SampleTableView is a member of UITableView, UITableViewDelegate & UITableViewDataSource. Next turn is for the SampleCell class and shown as below:

class SampleCell: UITableViewCell {
    
    let color = UIColor(red:132/255, green: 210/255, blue: 246/255, alpha: 1)

    override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        let iconMock = UIView()
        iconMock.backgroundColor = UIColor(red:170/255, green: 210/255, blue: 246/255, alpha: 1)
        iconMock.frame = CGRect(x: 16, y: 16, width: 60, height: 60)
        iconMock.layer.cornerRadius = 10
        self.addSubview(iconMock)
        
        var label = UILabel(frame: CGRectMake(25, 25, 30, 30))
        label.center = CGPointMake(30, 30)
        label.textAlignment = NSTextAlignment.Center
        label.text = "S"
        label.textColor = UIColor.whiteColor()
        iconMock.addSubview(label)

        let lineLeft:CGFloat = iconMock.frame.right + 16
        let lineMargin:CGFloat = 12
        
        let line1 = CGRect(x: lineLeft, y: 12 + lineMargin + 10, width: 100, height: 6)
        let line2 = CGRect(x: lineLeft, y: line1.bottom + lineMargin, width: 180, height: 5)
        addLine(line1)
        addLine(line2)
        
        let sepalator = UIView()
        sepalator.frame = CGRect(x: 0, y: 0, width: frame.width + 50, height: 1)
        sepalator.backgroundColor = UIColor.grayColor().colorWithAlphaComponent(0.2)
        self.addSubview(sepalator)
    }


    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    func addLine(frame:CGRect) {
        let line = UIView(frame:frame)
        line.layer.cornerRadius = frame.height / 2
        line.backgroundColor = color
        self.addSubview(line)
    }
}

Now that’s a lengthy amount of code, but no worries, we will understand it step by step. We first use the init function to declare the iconMock that shows a UIView to represent some kind of image label to the left position. Setting it’s layer, frame and color – we than add it to the main view. Next, we add UILabel named label which will provide an alphabet in the iconMock created above. The properties of textColor, textAlignment, center are set for the label as shown and added as a subView to the iconMock view.

Now we add some lines with rounded corners for little UI showcase. This will help us understand how the tableView works programmatically. We can also add them to storyboard and use it normally with ease if you don’t want this hassle. Now we add line1, line2 & separator lines to each table cell using functions of addLine added below the init frame.

So finally after adding this many code the file hierarchy of your Xcode project should be as shown below:

Hierarchy

That’s it! we have just mastered using a custom tableView programmatically as well as using the PullToRefresh functionality for elegant UI in your app.

Running the App

So now you run the app with the big “Play” button in the top left of Xcode.  You then need to set what device to run the app on.  You can select a physical device (if you have a paid developer license).  Otherwise, or even just for simpler testing, you can run it in the simulator.  Choose the simulated device to run it on from the same menu.

Then wait a bit while the simulator loads.  Mine took about 30 seconds to load.  Then pull the tableView down to reflect the animation.

Here is the source code on Github for the tutorial above !

I hope you found this article helpful.  If you did, please don’t hesitate to share this post on Twitter or your social media of choice.  The blog is still pretty new, and every share helps.  Of course, if you have any questions, don’t hesitate to contact me on Twitter @swifty_os, and I’ll see what I can do.  Thanks!

 

Advertisements