ListViews in Titanium Alloy - Part 1

avatar

By: Richard Lustemberg

Published to Code on Feb 18, 2015

(Demonstration code for this tutorial can be found at : https://github.com/rlustemberg/listviewtutorial)

You must use ListViews

TableViews and ListViews are very useful UI elements which allow for display of lists of data in a vertical scrollable way. TableViews were Titanium's original implementation of iOS’s UITableView and Android’s ListView widget.

There was a big issue with TableViews, they were really, really slow. By design, they couldn't scale. Instantiating every view (and callbacks) , for every row meant that although the app will be displaying no more than 10 rows at a time, out of sight there could be hundreds of rows eating up memory (and each one with it's subviews!)

Issues

  • After 20 rows, performance lags behind
  • UI becomes sluggish
  • Memory is allocated for every row and it's views (what happens if you have a few hundred rows?)

Appcelerator was aware of the issue (of course) , and in time they’ve released the ListView module built in on their mobile SDK (since 3.1).

Performance improvements

ListView’s are a 100th fold improvement over TableView’s in terms of performance. They no longer instantiate all of the rows as regular views.

They only generate the rows which are visible, and sort of juggle back and forth in that array of row data, using the row views as templates which are injected with data.

When displaying lists of data, it is a MUST to use ListViews. Unfortunately, in order to optimise for performance, some trade offs were taken such as to make the ui element as lean as possible. Mainly, all of the UI elements in the row cannot be accessed directly. You cannot add a callback to a click event on a button, and have the callback change something in the row (such as grey star icon into a yellow star icon).

(For a list of the API differences between TableView and ListView have a look at the Appcelerator’s documentation at http://docs.appcelerator.com/titanium/latest/#!/api/Titanium.UI.ListView).

Setting up a list view in Alloy

I’m going to use Alloy for the example. Using plain vainilla Titanium is somewhat more cumbersome with listViews, but easier to pickup once you understand how to do it in Alloy. There are four elements to take in consideration when working with ListViews:

Using the Alloy framework, they can all be instantiated in a single view markup file.

  • ListView
  • ListViewSection
  • ListViewItem
  • ListViewTemplate
<ListView onItemclick="listItemHandler" defaultItemTemplate="mainTemplate">
    <Templates>
        <ItemTemplate name="mainTemplate" id="mainTemplate">
            <View id="rowContainer">
                <View id="header">
                    <ImageView bindId="avatar" id="avatar"></ImageView>
                    <Label bindId="title" id="title"></Label>
                </View>
                <View id="imageContainer">
                    <ImageView bindId="pic" id="pic"></ImageView>
                </View>
                <View id="footer">
                    <Label bindId="bodyText" id="bodyText"></Label>
                    <View>
                        <View bindId="bookMark" id="bookMark" onClick="buttonEventHandler"></View>
                    </View>
                </View>
            </View>
        </ItemTemplate>
    </Templates>
    <ListSection id="listSection" headerTitle="Feed">
        <ListItem pic:image="/images/landscape.jpg" avatar:image="/images/colbert.jpg" title:text="Great Landscape" bodyText:text="ListView ..." bookMark:backgroundImage="/images/star_unselected.png"/>
        <ListItem pic:image="/images/landscape2.jpg" avatar:image="/images/oreilly.jpg" title:text="Mine's better" bodyText:text="ListView ..." bookMark:backgroundImage="/images/star_unselected.png"/>
        <ListItem pic:image="/images/landscape3.jpg" avatar:image="/images/colbert.jpg" title:text="What about this?" bodyText:text="LListView ..." bookMark:backgroundImage="/images/star_unselected.png"/>
      </ListSection>
</ListView>

ListView

This is the view that holds all of the rows. Click events on them are actually handled here. The events contain data about the row.

<ListView onItemclick="listItemHandler" defaultItemTemplate="mainTemplate">

The two crucial properties are:

  • defaultItemTemplate : it sets a default template for the items. if not set, you’ll have two define the ‘template’ property on each item
  • onItemClick: it’s the event handler for clicks on listItems. You declare the callback on the view’s controller.

ListSection

ListViews can have several sections, as TableViews do. The main difference is that adding items to the ListView can only be done at the ListSection.

<ListSection id="listSection" headerTitle="Feed">

We assign an id property so that we can reference the listSection from within the controller. The methods for the listSection which concern us now are:

  • setItems(itemsArray) : That’s how we add items to the section. It receives an array of ListItem objects as an argument
  • getItemAt (index) : Getting a ListItem object at a specified index (usually provided by the itemClick event from the ListView
  • updateItemAt(index, item): You can modify an item at a specified index. Usually you get the listItem object from the itemClick event, modify some of it’s properties, and then pass the item to this method.

There are also methods such as deleteItemsAt, insertItemsAt, replaceItemsAt which we’ll not be covering on this tutorial

itemTemplate

These are the actual views which will be used in the listItems. We declare them in the xml view files (they can be also created in a separate controller and required). Titanium provides default templates, but we will not deal with them. We’ll make our own, as we’ll have to on most projects.

<ItemTemplate name="mainTemplate" id="mainTemplate">
    <View id="rowContainer">
        <View id="header">
            <ImageView bindId="avatar" id="avatar"></ImageView>
            <Label bindId="title" id="title"></Label>
        </View>
        <View id="imageContainer">
            <ImageView bindId="pic" id="pic"></ImageView>
        </View>
        <View id="footer">
            <Label bindId="bodyText" id="bodyText"></Label>
            <View>
                <View bindId="bookMark" id="bookMark" onClick="buttonEventHandler"></View>
            </View>
        </View>
    </View>
</ItemTemplate>

You can see that the template is very similar to a view declaration. They are not the same though, which is obvious when you declare the template programatically in Titanium JavaScript, but less so in Alloy.

You can add class and id properties for further styling on a .tss file. Those id’s cannot be referenced in the $ object in the controller though (more on that later). The bindId property is what we use to map properties for the ListDataItem to the ListItem:

//in the controller                                 in the template
listItem.title.text = ‘Hello World’  ->  <Label bindId="title" id="title"></Label>

ListItem

The items themselves. Below an example in declarative xml , usually we handle listItems in the controller

<ListItem pic:image="/images/landscape.jpg" avatar:image="/images/colbert.jpg" title:text="Great Landscape" bodyText:text="text here" bookMark:backgroundImage="/images/star_unselected.png"/>

In short

  • For displaying lists of data use ListView instead of TableView. Always!
  • A ListView contains ListSection which contains ListItem's
  • ListItem instances are just data
  • The data on the listItem is used to configure the views defined on the item's template (itemTemplate)
  • Each listItem can define it's own template. Otherwise, they inherit the defaultItemTemplate defined in the ListView

I hope this tutorial can be useful for the readers. Feel free to comment with eventual questions or suggestions.

There is also a Part 2 for this tutorial, with tips on how to further implement ListViews.

Tags: Alloy, Beginners, JavaScript, Titanium

Categories

Tags