What happens here is that recycling doesn’t work as intended anymore.

Let’s say a big item scrolls out of view and its view template is put into the recycle pool and then reused as small-image item. The angular renderer will have to create all the views contained in the second ngIf and will destroy all the views form the first ngIf . The only reused part will be the wrapping StackLayout (which is not really needed anyway).

This means this will be slow and generate garbage at the same time. Here is how this looks like:

That was slow! We can clearly see the GC kicking in and freezing the scroll.

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.

No need for ngIf and therefore - no excessive creating/destroying of UI Views each time a view is recycled. As a bonus, we can get rid of the StackLayout that was previously just holding the 3 different templates.

And here is the code for that:

<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>

In the markup we define 3 different <template> elements giving each one a name using nsTemplateKey directive. We are also giving the ListView a itemTemplateSelector function that is defined in the component code. It should return the name of the template to be used given the actual item:

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!")

}

Let’s see how this behaves:

Neat! This is the performance we are looking for!