I'm not sure if this is a bug or something I'm missing. I have a simple TableView with several custom rows. By custom rows I mean I create a TableViewRow object and add a few views to it, instead of just providing a dictionary containing title and some other TableViewRow properties. See the API docs for TableView, specifically the "Creating Tables" section, to see the difference in row creation methods.
Anyhow, I also add a rowID property to each custom row (and to its children) so that my table click event listener can reference the proper row. The idea is that the event listener simply changes the background color of the row to blue when the row is clicked.
This all works great in iOS, and in Android when the number of rows in the table can all fit on the screen. But in Android, when I make more rows than can fit on screen, when I scroll down, I notice several issues:
1) One of the rows ends up not having the default red background and is apparently missing the label view. Yet when I click on that "broken" row, the event listener reports the correct rowID value via Ti.API.info().
2) After I have scrolled down to reveal the "broken" row, if I then start clicking elsewhere on the table, it starts acting erratically and not setting the background of the correct row to blue, yet the event listener still reports the correct rowID property, and I'm pretty sure I'm accessing the desired rowView correctly. Sometimes it will either not turn the row blue at all, and other times it will turn the wrong row blue.
I imagine internally that the mapping of the the TableViewRows and their child views are getting corrupted, but only when there are more rows than can initially fit on screen, and only in Android.
Here is the simple test case code to reproduce the problem:
var tableData = []; var win = Ti.UI.createWindow({ backgroundColor: 'white' }); var table = Ti.UI.createTableView(); for (var i = 0; i <= 20; i++){ // each of the below UI widgets gets rowID property because different platforms end up firing // gestures on different elements; however we don't care which element, as long as we know the // row of the table that fired an event var row = Ti.UI.createTableViewRow({ className: 'row', rowID: i, height: 40 }); var rowView = Ti.UI.createView({ layout: 'horizontal', backgroundColor:'red', rowID: i, width: Ti.UI.FILL, height: '100%' }); var rowLabel = Ti.UI.createLabel({ text: 'Row ' + i, rowID: i }) rowView.add(rowLabel); row.add(rowView); tableData.push(row); } table.setData(tableData); table.addEventListener('click', function(e){ Ti.API.info('click in table row: ' + e.source.rowID); // attempt to change clicked row to backgroundColor: blue // note that data[0] is the single TableViewSection that gets automatically added when table.setData() // was called; rows is the actual array of TableViewRow objects, which the rowID property should correctly index; // then children[0] is the single rowView child that was added to the TableViewRow table.data[0].rows[e.source.rowID].children[0].backgroundColor = 'blue'; }); win.add(table); win.open();This is using Titanium SDK 2.1.3.
2 Answers
Accepted Answer
I think the problems you're having are because you have set the className on the row. When you do this, rows are re-used when you scroll... that's the point of className.
Try removing className for what you're doing, and see if that solves the behavior issues.
Once confirmed, I would put className back for the rows (say 'normalRow'), and replacing your selected row with one of a different className (say 'selectedRow') using TableView.updateRow().
Don't set "rowID" on the child objects, only set it on the row. In your event, try e.rowData.rowID instead of e.source
Your Answer
Think you can help? Login to answer this question!