This documentation relates to previous versions of Titanium.

To see the latest documentation, visit docs.appcelerator.com.

Skip to end of metadata
Go to start of metadata

Objective

In this chapter, we’ll examine TableView basics then dig a bit deeper into what you can do with tables. We’ll look at headers, footers, and sections. Finally, we'll wrap up with a look at handling events associated with tables and rows.

Contents

Let's start by creating a table. You do so with the Ti.UI.createTableView() method, like this:

Some key table properties include:

  • height and width – controls the dimensions of the table; it doesn't have to fill its parent container
  • top and left – controls placement of the table, useful if you want to add buttons or labels above or below it
  • backgroundColor and backgroundImage – controls the background of the table; transparent is a valid backgroundColor
  • rowHeight / minRowHeight / maxRowHeight – controls table-wide dimensions of rows
  • headerTitle / headerView – controls the table's header
  • footerTitle / footerView – controls the table's footer
  • scrollable (boolean) – controls whether the table is scrollable (vertically)

Assigning data to your table

Next we'll move on to adding rows, which are the core of any table component. Let's take a look at the options that Titanium makes available to you for creating and adding rows.

Table rows are represented by the Ti.UI.TableViewRow object. This object contains various properties and methods that you can use to style and manage your table rows. You can create TableViewRow objects explicitly using the Ti.UI.createTableViewRow() function. Conversely, you can use simple Javascript object literals to represent your rows. For quick and dirty row creation, the object literal technique is likely faster and easier. When you want to carefully style and control the behavior of rows, though, you'll probably want to create explicit row objects.

Object literals as rows



Creating object literals in this way is very handy when pulling data out of a database or across the network. By explicitly creating TableViewRow objects, you gain access to a few handy methods such as add() or fireEvent().

Explicit TableViewRow objects

Emptying a table

You can empty a table by setting its data property to an empty array.

Do not set a TableView's data property to null or undefined as it will result un unexpected behavior.

Setting data vs. setData() vs. appendRow()

For best performance, create an array of row objects (object literals or explicitly typed) and then assign them to the table using either setData() or by setting the data property. In community tests, appendRow() performs significantly slower than setData() when adding thousands of rows to a test table. Though this is an uncommon scenario, it is still best to manage your tables, and all UI components, in the most performant manner possible.

If your app does however currently require a table with thousands of rows, you should may want to reconsider your UI. Users won't want to scroll through that many rows to find the one that interests them. Even on the fastest device, such a table will be slow. Consider some sort of drill-down interface, filtering mechanism, or alternate UI/UX paradigm to reduce the size of the available table.

Row properties

Now that we've seen how to create tables and rows, let's learn a bit more about the built-in row properties. TableViewRow objects have various useful properties that you can use to add style and functionality to your tables.

  • className – set this property equal to an arbitrary string to optimize rendering performance. On both iOS and Android, setting this property enables the operating system to reuse table rows that are scrolled out of view to speed up the rendering of newly-visible rows. On iOS, the string you supply is used to specify the reuse-identifier string (setdequeueReusableCellWithIdentifier); on Android, it is used within a custom object reuse method within Titanium.
  • leftImage – set this property equal to an image URL (local or remote) to display that image to the left of the row's title
  • rightImage – set this property equal to an image URL (local or remote) to display that image to the right of the row's title
  • backgroundImage – set this property equal to an image URL (local or remote) to display that image in the background of the row
  • backgroundColor – set this property to a color string to set the row's background color

So let's augment the properties of the prior TableView example rows. In the following code we'll utilize the above properties on a per row basis, making for a highly styled set of table rows.






Row indicators

Row indicators are icons that provide visual cues to your users related to your table rows. As shown in the following graphic, Android supports two built-in icons while iOS supports three. Each is a boolean value set with the property listed following the graphic.

  • hasChild – indicates sub-table or additional rows (most commonly used on iOS with the NavigationGroup control)
  • hasDetail – indicates a detail view or alert will appear when row is tapped (not supported on Android)
  • hasCheck – an on/off or yes/no indicator

Custom rows

If the stock properties don't suit your needs, you can add Views, ImageViews, Labels, Buttons, and so forth as children of your rows. This gives you enormous flexibility when laying out the content of your table. Make sure to set at least an "auto" height for the row so that the children elements will be visible.

Let's once again visit the example TableView code. This time we'll modify it to use explicit TableViewRows. To these TableViewRows we will add a label, button, and image in a custom format.

This is just one very simple example of how you can create custom rows for your tables. You can literally embed almost any Titanium UI component in any visual configuration to create your rows.

It is tempting to make heavy use of Titanium's flexibility with custom rows. You need to be aware, however, of the performance implications of making your rows overly complex. Each unique UI element you add to a row has resources requirements, and those requirements are magnified by the number of rows in your tables. Be sure to test both on simulator/emulator and device as you develop to ensure you are getting the app performance you expect, and scale back row complexity if necessary.

Grouped rows

On iOS, you can set the style property of the table to display table sections as separate components, as shown in the following graphic.

Headers and footers

You can use the built-in headerTitle and footerTitle to add header and footer titles to your tables. This convenience property allows you to enter arbitrary text for these titles, but will only use the default font formatting.




A more flexible technique is to use Views for your headers and footers. You can create a view and set it in the table's headerView or footerView properties. Here's an example of setting both the header and footer using these properties.

Table sections

Table sections enable you to create groupings of related rows within your table. Table sections can have headers and footers. You create sections with the Ti.UI.createTableViewSection() method. Then, you add rows to that section and set the table's data property equal to an array of sections. Like this:

Iterating over the rows in a table using Section

Titanium always creates at least one table section for you even if you don't explicitly create a TableViewSection. This is handy because sections have a rows property, which tables do not. This property stores an array of all the rows in that section. In other words, you can use sections to loop programmatically through the rows in a table.

Searching within a table

You can enable searching by adding a search bar to your tables. As users enter text, rows are filtered such that only those containing the text in their title property remain visible. The search is not a leading character search. In other words, searching for the letter "b" would display all rows containing that letter anywhere within their title.

As you can see in the image below, there are platform differences in the way the search bar is rendered. A couple of the properties used bear further explanation:

  • showCancel if true then show a cancel ("clear") button always. If false on Android never show that button; on iOS don't show Cancel until the user begins typing.
  • hideSearchOnSelection is an iOS only property. With it set to true as soon as the user taps a row in the search results, the search box is cleared and the Cancel button is hidden. Set it to false and the search text and button would remain. The default value is true Android operates as if this value were set to false

Events and event object properties

As shown in the preceding code, you can add event listeners to tables. From there, you can access sections, rows, and nested child elements. While you could add event listeners directly to the rows, we don't recommend it. Doing so adds unnecessary memory and processing overhead to your app. Also, it can be difficult and repetitive adding listeners to all the various rows.

As shown in the code above, you have access to an event object, e, that holds important table information within the listener. For example, some of the key properties of that event object include:

  • index – the ordinal index number of the row that received the event
  • row – the object representing the row that received the event
  • rowData – the properties of the row that received the event
  • source – the object that received the original event
  • section – the table section that received the event

Hands-on Practice

Goal

In this activity, you will create a custom table that doesn’t fill the entire viewport. The table will contain customized rows with background images that differ based on the row’s location within the table. Each row will contain two images and two labels. When you tap a row, an event listener will determine if either of the images was the object that received the tap. If so, that image will be swapped with an alternate graphic.

When completed, your app should match what is shown in this movie: http://assets.appcelerator.com.s3.amazonaws.com/video/320.mov

Resources

Download the starting point code from http://assets.appcelerator.com.s3.amazonaws.com/app_u/code/320.zip. This archive includes the necessary graphics.

Steps

  1. Download, extract, and then import the TableView project into Studio. Confirm that the tiapp.xml file has appropriate values then close that file. Open app.js in Studio.
  2. Following the comments included in the starting app.js file, add these elements to the app:
    • Set the window background to images/gradientBackground.png
    • Add a page heading of “Custom Table” with a dark blue, 18 px, bold font that is positioned at the top-left of the window
    • Define a table that is positioned below the label and which is 90% of the width of the screen and 85% of its height. Set the table’s background color to transparent and for iOS, set the separator style to NONE.
  3. Write a function named makeRow() following the specifications included in the comments within the code.
    • Your makeRow() function should accept an object that will be used to pass in four values: the row number, primary label text, secondary label text, and a custom “which image” indicator string. Possible values for the row number parameter will be an integer or the string ‘last’. Possible values for the myImage string property will be a, b, c, blue, and red. You’ll use this myImage property to determine which element in the row is tapped and to swap images accordingly.
    • Each row should contain two images:
      • Left image: if an even-numbered row = ‘images/imageA.png’ otherwise ‘images/imageB.png’. It should have a custom property named myImage that is set equal to the myImage parameter passed to your makeRow() function at run time.
      • Right image: use ‘images/notificationBadge.png’ and set its custom myImage property equal to ‘blue’
    • Each row should contain two labels:
      • Primary label: use a bold, 16 px font positioned to the right of the left image with its text set equal to the primary label parameter passed to makeRow() at run time. Be sure to set a height for the label.
      • Secondary label: use a bold, 13 px font positioned below the primary label with its text set equal to the secondary label parameter passed to makeRow() at run time. Be sure to set a height for the label.
    • Each row’s background image should be set to ‘images/middleRow.png’ and the selected background image to ‘images/middleRowSelected.png’. If the row number parameter is 0, set the row’s background image to ‘images/topRow.png’ and selected background image to ‘images/topRowSelected.png’. If the row number parameter equals ‘last’ then use ‘images/bottomRow.png’ and ‘images/bottomRowSelected.png’ for the background images and use ‘images/imageC.png’ for the left image.
    • The makeRow() function should return a Titanium.UI.TableViewRow object.
  4. Use a for-loop to create an array of 8 rows for your table, calling makeRow() in each iteration of the loop. Set the primary label to “This is row” plus the row-number indicator. Set the secondary label to “Subtitle” and the row-number indicator. Set the myImage value to either ‘a’ or ‘b’ depending on whether your loop counter is odd or even. (Hint: use the modulus operator, %, to calculate this odd/even value.)
    Push one additional row into the rows array. This row should pass these values:
    • row number: ‘last’
    • primary label: ‘This is the last row’
    • secondary label: ‘The last subtitle’
    • myImage: ‘c’
  5. Add a click event listener to your table. Check the myImage property of the event source. Using a switch or if-else test, determine if myImage is set equal to a, b, c, blue, or red. If a, b, or c, swap the left image such that imageA becomes imageB, imageB becomes imageC, and imageC becomes imageA again. If the myImage property equals blue, the right image should change to images/notificationUnreadBadge.png otherwise it should swap back to images/notificationBadge.png.
  6. Save and run the project in the simulator. Confirm that the user interface matches the screenshots shown below. Confirm that your event listener functions properly:
    • When the row is tapped, the background image should swap to the green “selected” version.
    • If the left image is tapped, the letter should advance to the next letter, looping back to the beginning properly.
    • If the right image is tapped, it should swap between the red and blue versions properly.

References and Further Reading

Summary

In this section, you reviewed TableView basics, then explored some of its more powerful functionality. We looked at headers, footers, and sections. Finally, we wrapped up with a look at handling events associated with tables and rows. In the next section, we'll see how we can add custom icons and splash screens to our Titanium apps.

Labels
  • None