Sharing my tableView experience and epiphany

Hi,

I want to share my experience from working with tableViews on data sources with an infinite number of rows, as well as a small epiphany i had concerning how to achieve a smoother scrolling.

I know there are other people in here struggling with similar performance issues, so hopefully someone will find this post useful.

My tableView do on-the-fly download and displaying of rather large images, which have to be formatted, scaled and positioned. I was always under the impression that this was the culprit for the a.m. performance issues.

So here is an example on how i used to add images to the rows in the renderer:

row.myImage=display.newImage("image.png") resizeImage(row.myImage) -- calls a simple image handling function row.myImage.x=25 row.myImage.y=25 row.myImage("mask.png") row.myImage.maskScaleX=0.8 row.myImage.maskScaleY=0.8

The result was typical with minor random jerky issues and less than optimal swipe performance. The larger the images, the more noticable the issues.

One day I discovered that if I change the code to look like this instead:

local myImage=display.newImage("image.png") resizeImage(myImage) -- calls a simple image handling function myImage.x=25 myImage.y=25 myImage("mask.png") myImage.maskScaleX=0.8 myImage.maskScaleY=0.8 row:insert(myImage)

the performance issues more or less vanished. Swipe was suddenly smooth again (you know the native ios scroll feeling, right?)

Examining the code, it makes perfect sense to wait until all display object altering code has been executed before inserting the object into the tableView, doesn it?  :wink:

The second thing I’d like to mention is how to deal with sources of infinite rows (loading as the user scrolls).

Adding many rows to a tableView in bulk can have performance issues and create scroll stutter. After several attempts I found a way to insert these rows, on demand, one by one, and never more then needed. This method yield the best scroll performance I’ve managed to produce.

Before the tableView renderer can render anything, it needs at least one row, so the first thing i do is to insert a single row, like this:

myTableView:insertRow({rowHeight=20,rowColor={default={1,1,1,0},over={1,1,1,0}}})

Then in the renderer function, as the last part of the code i add:

local position=math.abs(myTableView:getContentPosition()/row.height) local numRows=myTableView:getNumRows() local screenOffset=2+(display.contentHeight/20) if position\>numRows-screenOffset and numRows\<#myDataArray then myTableView:insertRow({rowHeight=20,rowColor={default={1,1,1,0},over={1,1,1,0}}}) end

The screenOffset formula must be modified to your exact tableView, but the logic to divide your tableView height by your standard row height. The added “2” just act as an off-view (tableView) trigger for inserting the next row.

This works easier all rows are the same height, but anything is possible as long as you can figure out how to calculate the total height of visible rows.

anaqim

EDIT - Rewrote post after Rob pointed out some issues.

These are some good observations @anaqim.

I have one of my own. Please be careful using “table” as a variable. In particular, if you end up making it a global it will write over the system table.* APIs.  And even if you make it local, you won’t have access to them.

Rob

Hi Rob,

Thanks, I only used that in the code as examples, trying to make it more generic/understandable.

I could have explained it better, sorry about that, will fix the original post.

You are of course right that in live code, it is better practice to only use unique variable names.

anaqim

These are some good observations @anaqim.

I have one of my own. Please be careful using “table” as a variable. In particular, if you end up making it a global it will write over the system table.* APIs.  And even if you make it local, you won’t have access to them.

Rob

Hi Rob,

Thanks, I only used that in the code as examples, trying to make it more generic/understandable.

I could have explained it better, sorry about that, will fix the original post.

You are of course right that in live code, it is better practice to only use unique variable names.

anaqim