Skip to content

Latest commit

 

History

History

table-view

9 minutes tutorial

Table View

Build an API-backed table in minutes, right from Interface Builder!

Example: Chatting app

API URL: https://api.abstractlayer.com/demo/silicon_valley/get_users

Click the arrow to check out the full JSON response
<pre><code>[

{ "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/richard-hendricks.jpg", "timestamp": 1491631526, "last_message": "Thank god they use tabs!", "name": "Richard Hendricks", "id": "5925b5ac22f9a51d0ca5a3ce" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/guilfoyle.jpg", "timestamp": 1491639798, "last_message": "This framework is better than hell.", "name": "Guilfoyle", "id": "5925b5ac58cff049f195e566" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/dinesh.jpg", "timestamp": 1491633121, "last_message": "I can’t believe Guilfoyle actually loved something other than himself.", "name": "Dinesh", "id": "5925b5ac71aef5f0f3febd4a" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/jared.jpg", "timestamp": 1491634194, "last_message": "Based on my SWOT analysis, this framework is a great investment.", "name": "Jared", "id": "5925b5ac6af1272071a57d72" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/jian-yang.jpg", "timestamp": 1491634511, "last_message": "This is not a hotdog.", "name": "Jian Yang", "id": "5925b5acdfecdab484513b96" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/erlic-bachman.jpg", "timestamp": 1491642125, "last_message": "Abstract Layer is the intersection of spirituality and automation.", "name": "Erlic Bachman", "id": "5925b5acec7ff952f35a65eb" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/laurie-bream.jpg", "timestamp": 1491633389, "last_message": "Is Abstract Layer raising?", "name": "Laurie Bream", "id": "5925b5ac9b66bc12c486cdfb" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/gavin-belson.jpg", "timestamp": 1491641044, "last_message": "Why again did Hooli not build this framework?", "name": "Gavin Belson", "id": "5925b5acff14642da4571ef2" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/russ-hanneman.jpg", "timestamp": 1491630862, "last_message": "This framework f*cks!", "name": "Russ Hanneman", "id": "5925b5ac42c8cdfb0c17664d" }, { "image_url": "http://docs.abstractlayer.com/demo/table-view/silicon-valley/images/big-head.jpg", "timestamp": 1491639079, "last_message": "Woah this Abstract Layer thing is awesome!!", "name": "Big Head", "id": "5925b5ac29f5b9e382590e1a" } ]

Table view

Integrate the framework

If you haven't already added the framework to your Xcode project, follow this tutorial.

Build the UI

  • Open Main.storyboard and delete the default view controller

  • Drag an instance of UITableViewController From the menu bar choose:

Editor → Embed in → Navigation Controller

  • Click on your navigation controller then check the box that says Is initial View Controller from the Attributes Inspector

Table view

  • Click on your prototype cell, and set the cell identifier to cell in the Attributes Inspector

  • Drag the prototype cell in your storyboard from the bottom to increase its height to 80

  • Design the tableview's cell to match the design

    Table view
    • UIImageView for the user image (size 50x50)
    • UILabel for the name label (Font size 13, semibold, black)
    • UILabel for the last message label (Font size 12, regular, dark gray)
    • UILabel for the date label (Font size 12, regular, light gray)
  • Choose 2 lines for last message label

Table view

Magic (Auto data-binding)

It's time to bind data between the JSON document and the UI elements.

Table view

  • Navigate to your Attributes Inspector, and you'll find a list of new attributes

  • Paste the URL you just copied in the new Url field

  • Type in GET for HTTP method

Table view

Your table view is now ready to process the API. It's time to match the JSON keys with the UI elements to fill the data automatically.

User Image

  • Click on your UIImageView and change its class to ALImageView in the Identity Inspector

Table view

  • Type in image_url in the Json Key field so that Abstract Layer can automatically load the image using its URL value

Table view

Circular Image

To get a circular user image, turn the circular option ON.

Table view

Name Label

  • Click on the name label and change its class to ALLabel in the Identity Inspector

Table view

  • Type in name in the Json Key field to automatically match the JSON value with the name label

Table view

Last Message Label

  • Click on the last message label and change its class to ALLabel in the Attributes Inspector

  • Type in last_message in the Json Key field

Date Label

  • Click on the date label and change its class to ALDateLabel in the Attributes Inspector

Table view

  • Type in timestamp in the Json Key field

  • Type in MM/dd/yyyy in the Output Format field to get the desired date format displayed.

The format should abide by Apple's DateFormatter rules

Table view

Handle any kind of error by checking the Error handling section

Table view

Run the project, and there you go! MAGIC!

Hold on

This looks great so far, but we're sure you've got many questions about how far can Abstract Layer go.

Error Handling

Handle all kind of errors when loading your table view


Passing Data

You have FULL access to parsed data, so passing it is very simple


Parameters

Be it Header or Body, Static or Dynamic, it's all in Interface Builder


Pagination

Enabling pagination takes less than a minute


Complex JSON

Any form of JSON is supported, no matter how complex it is


Loader

Enable loaders and pull-to-refresh with 2 clicks


The example below shows how you can fully customize the table view example by modifying the parsed data before displaying it.

Display "Today" & "Yesterday" instead of full "MM/dd/yyyy" date

Remember: ALTableView is a subclass of UITableView

Remember: You have FULL access to the data parsed by accessing the array property on your Table view

  • Create a new class, call it CustomTableViewCell

Table view

  • Set the Table view cell class to CustomTableViewCell

Table view

  • Control-drag your date label to the class as a new outlet and call it dateLabel

  • Don't forget to import AbstractLayer to the class's header

Table view

  • Create a new class, call it TableViewController and subclass it form UITableViewController

Table view

  • Set your table view class in storyboard to TableViewController

Table view

  • Replace the content of the class with the following:
Objective-C Swift

import UIKit
import AbstractLayer

class TableViewController: UITableViewController {

// // MARK: Lazy load // private lazy var today:Double = { var calendar = NSCalendar.current calendar.timeZone = NSTimeZone(abbreviation: "UTC")! as TimeZone return calendar.startOfDay(for: Date()).timeIntervalSince1970 }()

private lazy var yesterday:Double = { var calendar = NSCalendar.current calendar.timeZone = NSTimeZone(abbreviation: "UTC")! as TimeZone return calendar.startOfDay(for: Date().addingTimeInterval(-86400)).timeIntervalSince1970 }()

// // MARK: Table view datasource // override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let table = tableView as! ALTableView let cell = table.cellForRow(at: indexPath) as! CustomTableViewCell

// Get item info
let array = table.array.first as! [[String:Any]]
let item = array[indexPath.row] // Get item dictionary
let timestamp = item["timestamp"] as! Double

// Date calculations
if timestamp > today {
  cell.dateLabel?.text = "Today"
} else if timestamp > yesterday {
  cell.dateLabel?.text = "Yesterday"
}

return cell

}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return tableView.numberOfRows(inSection: section) }

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let table = tableView as! ALTableView return table.heightForRow(at: indexPath) } }


#import "TableViewController.h"
#import <AbstractLayer/AbstractLayer.h>
#import "CustomTableViewCell.h"

@interface TableViewController () @property (nonatomic, assign) NSTimeInterval today,yesterday; @end

@implementation TableViewController

// // UITableView Datasource //

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [tableView numberOfRowsInSection:section]; }

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    CustomTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

    // Get item info NSArray *array = [(ALTableView *)tableView array].firstObject; NSDictionary *item = array[indexPath.row]; CGFloat timestamp = [item[@"timestamp"] doubleValue];

    // Check dates if (timestamp > self.today) { cell.dateLabel.text = @"Today"; } else if (timestamp > self.yesterday) { cell.dateLabel.text = @"Yesterday"; } return cell; }

  • (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [(ALTableView *)tableView heightForRowAtIndexPath:indexPath]; }

// // Lazy Instantiation //

  • (NSTimeInterval)today { if (!_today) { NSCalendar * calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; [calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; _today = [calendar startOfDayForDate:[NSDate date]].timeIntervalSince1970; } return _today; }

  • (NSTimeInterval)yesterday { if (!_yesterday) { NSCalendar * calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; [calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; _yesterday = [[calendar startOfDayForDate:[NSDate date]] dateByAddingTimeInterval:-86400].timeIntervalSince1970; } return _yesterday; }

@end

Table view

  • Run the app

So is it really 100% customizable? Can I actually use Abstract Layer in production?

Abstract Layer is as customizable as anything built from scratch.

As you've seen in the example above, the framework is fully customizable since it's built on top of native Apple UIKit components like UITableView & UICollectionView.

To customize any aspect of Abstract Layer, simply:

  • Subclass any of Abstract Layer classes to do your customizations
  • Conform to the delegate and datasource protocols just as you would do with a regular UITableView & UICollectionView

Abstract Layer is not a prototyping tool, it's strictly a production-level framework. All of our customers rely on Abstract Layer in their live apps.

Where to go next?

Abstract Layer supports lots of features on ALTableView, so make sure to check them all out!

<tr>
<td class="row-text"><b><a href="/#/menu/table-view/xib" target="_blank">XIB</a></b><p>Reuse cells by designing them in their own XIB</p><br/></td> 
<td class="row-text"><b><a href="/#/menu/table-view/authentication" target="_blank">Authentication</a></b><p>JWT is handled automatically once you provide your keys</p><br/></td> 
<td class="row-text"><b><a href="/#/menu/table-view/custom-cases" target="_blank">And More...</a></b><p>Check out the dedicated section for custom cases</p><br/></td> 
Error Handling

Handle all kind of errors when loading your table view


Passing Data

You have FULL access to parsed data, so passing it is very simple


Parameters

Be it Header or Body, Static or Dynamic, it's all in Interface Builder


Pagination

Enabling pagination takes less than a minute


Complex JSON

Any form of JSON is supported, no matter how complex it is


Loader

Enable loaders and pull-to-refresh with 2 clicks


Download the final project and try it out