Static Tables in Code


August 8, 2014

While there are a lot of great gems and tools to help us with creating great looking user interfaces in code in RubyMotion, sometimes I still like to explore how to do stuff at the iOS API level without using all the magic. Especially when just writing the code turns out to be pretty straightforward and elegant all on its own.

Creating a static table in code, to display some detail data in your application is one of these cases.

For my specific example, I have 6 items of information about a well to display, and this data logically groups into 3 sections of 2 items in each section. So, we’ll set up the table view using sections like so:

class WellDetailsController < UITableViewController

  SECTIONS = %w(Name Status Location)

  def viewDidLoad
    super
    navigationItem.title = "Well Details"
    self.tableView.allowsSelection = false
    self.view.registerClass(WellTableViewCell.self, forCellReuseIdentifier:self.class.name)
  end

  def viewWillAppear(animated)
    navigationController.setNavigationBarHidden(false, animated:true)
  end

  def numberOfSectionsInTableView(tableView)
    SECTIONS.size
  end

  def tableView(tableView, numberOfRowsInSection:section)
    2
  end

  def tableView(tableView, titleForHeaderInSection:section)
    SECTIONS[section]
  end

With this code, I have set up my 3 sections (Name, Status, and Location) as a constant array. Then we implement the necessary methods of the table view ( numberOfSectionsInTableView, tableView:numberOfRowsInSection, and tableView:titleForHeaderInSection) to deal with these sections.

Next up, we need to fill the actual table cells with data:

  def tableView(tableView, cellForRowAtIndexPath:indexPath)
    cell = tableView.dequeueReusableCellWithIdentifier(self.class.name) 
    cell.textLabel.text = @details[indexPath.section][indexPath.row][:label]
    cell.detailTextLabel.text = @details[indexPath.section][indexPath.row][:value]
    cell
  end

  def showDetailsForWell(well)
    @details = [
      [
        {label: 'UWI', value: well.uwi_display},
        {label: 'Well Name', value: well.well_name},
      ],
      [
        {label: 'Current', value: well.status},
        {label: 'Updated', value: well.status_date.strftime('%Y-%m-%d')},
      ],
      [
        {label: 'Latitude', value: well.latitude.stringValue},
        {label: 'Longitude', value: well.longitude.stringValue},
      ]
    ]
    tableView.reloadData
  end
end

Here, we set up the traditional tableView:cellForRowAtIndexPath. In it, we pull the data for the cell textLabel and detailTextLabel out of our @details data structure. This data structure is an array of arrays. More specifically, it is an array of sections, and each section array contains an array of rows. Each row is a hash, with a label/value pair.

The @details data structure itself gets populated with new values (the labels don’t change) when a well is selected in another view (from a list of wells, or a map of wells). The showDetailsForWell gets called, and then this view is displayed.

That’s all folks.

Certainly, it would be far simpler to code this up using Promotion, assuming you already knew and used Promotion. But it wasn’t necessary to add another gem to my project for this. And I now understand exactly how sections and rows work in UITableViewController, so it wasn’t a total loss ;-)