Chapter 17. Creating Lists and Tables

When you have a list of repetitive visual information to display then Storyboard's table's are a convenient tool to use. A table is equivalent to a control repeatedly applied, almost as a stamp or a template, to a grid of row and columns. A table with a single column or row can very effectively be used to represent list items. The controls that are created based on the number of rows and columns are referred to collectively as table cells. A table cell is a control at a particular one (1) based row and column offset. Tables offer automatic scrolling_layers capabilities, both interactively through touch events or programmatically using the Table Navigate and Table Scroll actions.

To create a scrolling table that is dynamically populated with data, you will generally follow these steps:

The data that is being used for the table can come from a variety of sources, but is generally processed into the table cell variables using Lua. For example, your data from a database, a file on the filesystem or dynamically injected into the application as an event via Storyboard IO. Once you have your data you will be able to process it and assign the appropriate fields into cell variables that the control templates reference. The following is an example of Lua data to be used in a table that was taken from the AddressBook > Sample application shipped with Storyboard:

        
local contacts = {
       {image=”images/john_smith.jpg”, first_name=”John”, 
       last_name=”Smith”, number=”453-555-1685”},
       {image=”images/jane_smith.jpg”, first_name=”Jane”,
       last_name=”Smith”, number=”466-555-1686”}
}

With an idea of what the table data looks like, you can build a control template to be used in the table that will display this content. Tables are created the same way as standard controls, by right clicking in the editor or Application View and selecting Add > Table or by dragging a Table Control from the editor palette. The New Table dialog offers a few additional configuration options to allow you to specify an initial number of rows, columns as well as defining the render extensions for the table and the first table cell control template.

In the case of the data we have above, we might consider creating a table with a single column and a table cell control template that contains an image render extension (for the image) and a two text render extensions (for the name and number. The image name, and text content properties would each be bound to a table cell variable to allow each table cell to contain a unique value.

In general the number of rows and columns that you create on a table that will contain dynamic content is only going to be as large as you need it to be to show the design intent. With external data populating the table, you will size the table appropriately using the Lua API gre.set_table_attrs(). In our sample we have our data in a Lua table so we can easily extract determine the number or rows for the table to be, your application data may use a different protocol.

 
function CBInitTable()
    -- Assume that tableLayer.table refers to our table
    gre.set_table_attrs(“tableLayer.table”, {rows = #contacts})
end

This will configure the internal size of the table to the size of our contacts list. Once the table is dynamically sized, we can start filling content by assigning values to our table cell variables. This represents the transfer of model data to visual domain data as the Storyboard variables represent content that will be directly reflected in the UI. Table cell variables are accessed using their basename and a .row.col index:

        
function CBInitTable()
    -- Assume that tableLayer.table refers to our table
    gre.set_table_attrs(“tableLayer.table”, {rows = #contacts})

    -- Assume we've created cell variables named image, name and number
    local data = {}
    for (row=1,#contacts) do
        data[string.format(“tableLayer.table.image.%d.1”, row)]
        = contacts[row].image
        data[string.format(“layer.table.name.%d.1”, row)]
        = string.format(“%s %s”, contacts[row].first_name, contacts[row]
        .last_name) 
        data[string.format(“layer.table.number.%d.1”, row)]
        = contacts[row].number 
    end
    gre.set_data(data)
end

With this functionality in place the table is now being sized appropriately and it's display content is being set.

If the content is too large to fit within the bounds of the table, then we will want to consider some sort of scrolling strategy. Storyboard offers two different scrolling strategies:

Cell based scrolling using Actions and cell re-positioning
Pixel based scrolling using table xoffset and yoffset

It is not suggested to mix and match between the two techniques.

The cell based scrolling is performed by changing the cell that is located at the top left most corner of the visual table. This is performed using the Table Navigate or Table Scroll actions. These actions provide flexibility with regards to the roll-over of content as well since they are simply manipulating which cells are being displayed.

The pixel based scrolling is generally what users are expecting within a modern interactive UI. This scrolling is enabled by selecting the Enable Scrolling property in the table's Table section of the Properties View. Enabling this option will unlock various properties that regulate the rate at which the table scrolls through its decay and virtual friction. These properties, and the ability to synchronize scrolling content with other controls is discussed in Chapter 18, Working with Scrolling Content.