Switching from TableView to ListView in Titanium: A Practical Guide
Replace a heavy TableView with Titanium’s ListView to lower memory use and keep scrolling smooth. Follow our step‑by‑step guide, including XML templates, controller binding, performance checks, and recovery steps.
23 Nov 2025, 08:54 UTC

Desired Outcome
Replace a Ti.UI.TableView that displays hundreds of rows with a Ti.UI.ListView that uses declarative item templates and Alloy data binding, achieving lower memory usage and smoother scrolling on both iOS and Android.
Prerequisites
- Installed Titanium SDK 7.0.0+ (verify with
ti sdk list). - Alloy project structure (app/ folder with
views,controllers,models). - Basic knowledge of Alloy XML and JavaScript.
- Device or emulator with at least 512 MB RAM for realistic performance testing.
Procedure
- Define the item template in XML.
<Alloy> <View> <ListView id="contactList" defaultItemTemplate="contactTemplate"> <ListSection> <!-- Sections will be populated from the controller --> </ListSection> </ListView> <ItemTemplate id="contactTemplate" bindId="contact"> <View layout="horizontal" height="50dp"> <ImageView bindId="avatar" width="40dp" height="40dp" left="5dp"/> <Label bindId="name" left="10dp" color="#000"/> </View> </ItemTemplate> </View> </Alloy> - Populate the ListView from the controller.
$.contactList.sections = [ Ti.UI.createListSection({ headerTitle: 'Contacts', items: generateContactItems(500) // returns an array of objects }) ]; function generateContactItems(count) { const items = []; for (let i = 0; i < count; i++) { items.push({ contact: { avatar: 'avatar.png', name: 'Contact ' + i } }); } return items; } - Handle item clicks using the event’s section and itemIndex.
$.contactList.addEventListener('itemclick', function(e) { const section = e.section; const index = e.itemIndex; const item = section.items[index]; Ti.API.info('Clicked: ' + item.contact.name); }); - Perform incremental updates.
// Append a new contact without rebuilding the entire list const section = $.contactList.sections[0]; section.appendItems([{ contact: { avatar: 'avatar.png', name: 'New Contact' } }]);
Expected Checks
- Verify the correct template renders: open the app, scroll, and ensure each row shows the avatar and name as defined.
- Confirm
itemclickpayloads containsectionanditemIndexthat match the displayed row. - Measure memory: use
ti profileon a physical device to compare RAM consumption after 500 items vs. a TableView version. - Test scroll performance: record FPS on both iOS and Android; ListView should maintain >30 fps with 500 rows.
Recovery Options
- If a custom template causes rendering glitches, replace the
ItemTemplatewith a singledefaultItemTemplatethat uses only aLabeland retry. - Should incremental
appendItemslead to jank, replace the entiresection.itemsarray in one assignment instead of mutating in place. - When encountering compatibility issues on a specific platform, fall back to
Ti.UI.TableViewfor that platform while keeping ListView for the other.
Limitations & Verification
ListView’s API surface and event payloads differ between SDK 7.x and later releases. After any SDK upgrade, re‑run the memory and FPS tests. The example uses placeholder image paths; replace them with actual assets. Because ListView relies on the Kroll bridge, avoid heavy synchronous work inside binding callbacks.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.