Faster NativeScript ListView with Multiple Item Templates

Background

Under the hood NativeScript uses the native list controls to render ListView. The smooth as butter scrolling in these controls depends on two major features:

  • UI Virtualization — Views are created only for the items that are currently visible. Fewer elements in memory => less memory footprint.
  • View Recycling — Whenever an item scrolls out of the view port, the view that was rendering it is not destroyed. It is put in a pool of recycled views and reused when an new item scrolls into view.
Virtualization (left) and Recycling(right)

Rendering Different Items

Sometimes we need to render collection with different items and we need to use different templates for them. Let’s say we are showing a collection of news items. Some items are big, some small, and some of the small ones have images and some don’t.

Using Single Template

If you have been using angular for while, you might be tempted to apply some ngIf/ngSwitch magic. You will probably end up with something like this:

<ListView [items]="items">
<ng-template let-item="item">
<StackLayout>
<GridLayout *ngIf="item.type === 'big'">
<!-- big item template -->
</GridLayout>
<GridLayout *ngIf="item.type === 'small' && item.imageUrl">
<!-- small item with image -->
</GridLayout>
<GridLayout *ngIf="item.type === 'small' && !item.imageUrl">
<!-- small item with no image -->
</GridLayout>
</StackLayout>
</ng-template>
</ListView>

The Better Approach

Luckily there is a cure. There is a way to instruct the ListView to use different item templates based on the item criteria you define. The good part is that it will keep the recycled views in different pools and will recycle a view form the right pool when needed to render the next item. The only thing that will have to change are the bindings — no creating/destroying views.

<ListView [items]="items" [itemTemplateSelector]="templateSelector">
<ng-template nsTemplateKey="big" let-item="item">
<!-- big item template -->
</ng-template>
<ng-template nsTemplateKey="small" let-item="item">
<!-- small item with image -->
</ng-template>
<ng-template nsTemplateKey="small-no-image" let-item="item">
<!-- small item with no image -->
</ng-template>
</ListView>
public templateSelector(item: NewsItem, index: number, items: NewsItem[]) {
if (item.type === "big") {
return "big"
}

if (item.type === "small" && item.imageUrl) {
return "small";
}
if (item.type === "small" && item.imageUrl) {
return "small-no-image";
}

throw new Error("Unrecognized template!")
}

Conclusion

Here is the code for both super slow *ngIf template and for the ultra fast template selector. Final thougths:

  • ngIf in ListView item templates: 👎🐌👎
  • Multiple templates + template selector: 👍🚀👍

--

--

NativeScript core member. Co-organizer of Angular Sofia. Father of a (future) rockstar.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alexander Vakrilov

Alexander Vakrilov

78 Followers

NativeScript core member. Co-organizer of Angular Sofia. Father of a (future) rockstar.