Creating Lists with the TableView Widget

Posted by

Corona TableView WidgetWith the relatively recent update to the widget library in build 2012.721, we released a tutorial on how to use the revamped ScrollView widget, but that’s not the only thing that was updated in Corona’s widget API.

If you’ve been paying close attention to the daily build logs, you probably noticed there have been several updates to the TableView widget since then. So for this week’s “Tutorial Tuesday”, I’ll be walking you through the creation one of the most commonly seen user-interface elements across all mobile apps: lists.

No matter what kind of app you’re developing, chances are good that one of these days, you’re going to need to display information in some kind of list. Thankfully, Corona’s TableView widget is perfectly suited for just that purpose! Our goal was to create a powerful, flexible widget that allows you to create lists of data—all while keeping simplicity and the developer experience in mind.

And although there may be some “tough spots” in terms of getting a really solid grasp on how to use it, I think we struck a good balance between ease-of-implementation and flexibility with the TableView widget.

Before you continue with the tutorial, please download the latest Daily Build to ensure you have access to all the necessary TableView features that we’ll be using.

The TableView widget is probably one of the most complicated widgets that are available, so this tutorial will be broken down into several sections that show you how to take advantage of each of its features. Each section will build off of the previous example before it. To get a more complete understanding of how to use the TableView widget, be sure to read all sections carefully, and in order.

Creating the Widget

This is the easiest part. We create the tableView widget and assign it to a variable called list using widget.newTableView(). If you cannot see the code below, go here to view it.

As you can see from the example above, we are creating a TableView with specific dimensions (in this case, 320×366) and have specified a PNG to use a mask for the TableView. It’s important to note that TableView widgets will not be clipped properly unless you specify a compatible mask file. Fortunately, masks are easy to create, and we have a separate tutorial dedicated to showing you how to create bitmap masks specifically for use with TableViews and ScrollViews.

Moving on, the example shown above is fairly minimal. There are several other parameters you can pass when creating the TableView widget. Please refer to the TableView API Documentation for a complete listing of these parameters.

Inserting and Deleting Rows

An empty TableView widget isn’t much use to us, so let’s insert a single row. Of course, the real benefit of using the TableView widget is having several rows, but we’ll take baby steps so things are easier to understand. Once we successfully create the row, we’ll remove it (just so you can see how it’s done). Please visit this page if you cannot see the code example below.

Once again, there are several other parameters associated with the insertRow() method, so consult the API documentation for a full listing. However, we’ll be using this function more in the following steps so you might want to wait a moment before exploring this API further.

onRender Listener

The most important parameter when inserting a row is the onRender parameter, because this is the function that will be called to create the row display object. By default, a row consists of only a background rectangle (accessed within the onRender listener via event.background) and a line (used to visually separate the row from others—accessed within the onRender listener via event.line).

When writing your onRender listener function, you should create any and all display objects you want your row to display. Whenever you create a display object, you must insert it into the event.view display group or it will not be rendered properly (and can potentially cause severe memory leaks in your app).

You can access the actual row object via event.row and the TableView that the row belongs to via event.parent. You can also assign references to your display objects to the row object if you need to access the objects from other rows, or elsewhere in your app.

All row objects are stored in the tableView.content.rows table, so in the case of our example, it would be list.content.rows.

Performance Advice

Depending on the amount of rows you have and how “heavy” they are in terms of what’s included, list scrolling performance can be greatly degraded (especially on device) if you’re not careful about optimizing what goes into each row (e.g. what you put into your onRender listener function).

Here are some “best practices” when it comes to creating your onRender listener function:

  • Make your rows as “light” as possible by doing away with as many unnecessary elements as possible. If your app can possibly live without something in a TableView row, it’s best to just leave it out.
     
  • Use as little vector shapes and text as possible. When using text, if it is predictable (and especially if it will be repeated in other rows), consider rasterizing the text to an image and use the image instead. Images can be cached in OpenGL while vector shapes and text cannot, so whenever possible, choose images over shapes and text.
     
  • Avoid using gradients (created using graphics.newGradient() in row rendering) — once again, stick to images or avoid gradients altogether if at all possible.
     
  • Avoid creating a new background for row, and instead take advantage of the already-created event.background if you need to change the row’s background color.
     
  • If possible, break up your content into several different lists (perhaps via the TabBar widget?) if your app requires very long lists.
     
  • If performance issues seem to only occur during really fast

Depending on your app and the kind (and amount) of data you need to display in a single TableView widget, you might find that performance is still not where you want it to be. For these cases, you might consider setting your app’s FPS to 30 (in config.lua) and see if that helps with TableView scrolling performance. You might also try adjusting the TableView friction and maxVelocity (set via parameters when calling widget.newTableView).

Adding Several Rows

Chances are, you’ll want to add more than a single row, but there’s also a good chance that many of your rows will resemble one another and have just a few differences. A great way to reduce the amount of code needed to add multiple row items is to place all your row creation code (which includes your onRender listener) in a for-loop and take advantage of event.index and event.id to differentiate between the different rows.

Here’s a revised version of the previous example (minus the deletion at the end), but this time it’ll insert 25 rows instead of just one (go here if you cannot see the code below):

Handling Row Touches

Now that you know how to to display information in a list using the TableView widget, it’s time to make your tableView content interactive by allowing it to respond to touches.

Row touches are handled via a separate listener which is specified via the listener parameter when you call tableView:insertRow(). This listener has several phases, which include: tap, press, swipeLeft, swipeRight, and release.

If you cannot see the code below, visit this page to view it.

Once again, the above example is a modified version of the previous example but with a few notable differences:

  • The onRowTouch function has been added to serve as the row’s listener for user touches.
     
  • In the onRender function, we create a reference to the text object (row.textObj) so the object can be accessed outside of the function (in the example, it is used in the onRowTouch function)
     
  • The listener parameter is assigned a reference to the onRowTouch when we call the TableView’s insertRow() method.
     

The phases within the row’s listener function (touch, tap, swipeLeft, swipeRight, and release) are all fairly self-explanatory (and even more-so if you ran the example in the Corona Simulator), but there is one property that is used in the “release” phase that should be explained further.

When you set the reRender property to true, this tells the TableView to destroy the row and re-render it (per its onRender listener) on the next TableView update (which is very frequently). By setting row.reRender to true in the “release” phase, we are telling the row to go back to it’s original state before it was touched.

Category Items

Another great feature of the TableView widget is the ability to specify “category” rows, which are rendered (and behave) identically to other rows, with one exception: category items will “stick” to the top of the TableView widget when they are scrolled to the top, and will push other category items up (if there are any currently stuck).

To specify a row as a “category”, you simply set the isCategory parameter to true when you call the insertRow() method. Category rows have an additional property, isCategory, which is useful in differentiating category items from normal row items within your listener functions.

Additional Resources

And that concludes our tutorial! If you didn’t follow along during the tutorial, I recommend going through it at least one more time while typing the code in so you get a better understanding of how to use the widget.

Also, don’t forget to consult the (just updated) TableView API Reference for more information on all the different parameters, properties, and methods associated with the TableView widget and rows.

For a working example, please see the WidgetDemo located in: /SampleCode/Interface/WidgetDemo in the Corona SDK download.

As a reminder, the conventions used by this tutorial require the most recent TableView changes, so be sure to download the latest build for best results. If you’re a trial user, subscribe today so you can take advantage of the best of the TableView widget and other cutting-edge features being pushed in on a regular basis.

Ready to get started?

Create amazing games and apps for iOS & Android

6 Comments

MitatenJanuary 31st, 2012 at 7:40 am

Good tutorial :-)

Mike MFebruary 1st, 2012 at 1:35 am

Good tutorial, but unfortunately there is still no feature to reRender the whole TableView.

Ben LynchFebruary 25th, 2012 at 2:41 pm

Having problems getting this to work using windows and the android simulator. Read some where that the setReferencePoint works differently in android and iOS, is that true? What, if there is one, the work around for android?

MichaelMarch 11th, 2012 at 7:57 am

Thanks for tutorial!

Don’t understand how to get a row object from outside the function? For example, how to print the text from the 5th row of the list from your Example 3?

MarcoMarch 17th, 2012 at 9:59 am

Hi,
I built an app using build 704 of the TableView widget. Now I want to upgrade my app, but am running into severe problems with the lists.
I’m using build 767 at the moment. Running on an iMac with 10.7.3 and Xcode 4.3.1.
When I copy-paste Example 4 from this tutorial, it simply doesn’t work.
First of all to get any text visible, I need to set the setTextColor(0). No problem there.
But then all the lines are bunched up together on the top line.

After some trail-and-error I managed to get my lists to be visible, but now when I touch a row, the keyboard I created and which is underneath the list, takes the touch instead of the list. With the old tableview widget this did not happen.

Can you please explain how to avoid this?

thx,

Marco

RickMay 19th, 2012 at 10:53 am

Marco I am using the same build as you and it dos not work for me either

Leave a comment

Your comment