Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView anchor rows to bottom

I have a UITableView that needs to introduce new content from the bottom. This is how a table view behaves when the view is full and you add new rows with animation.

I was starting it by altering the contentInset as rows are introduced but then when they change things go off, and the entry animation is all wrong... My problem with this approach is compounded by the fact that users can delete rows, and the row contents update, causing them to resize (each row has it's own height which changes).

Any recommendations on how to get a UITableView rows to always appear at the bottom of the UITableView's view space?

like image 377
ima747 Avatar asked Apr 15 '11 16:04

ima747


4 Answers

I've got a solution that works for me perfectly, but it causes a bunch of double thinking so it's not as simple in theory as it is in practice... kinda...

Step 1, apply a transform to the table view rotating it 180deg

tableView.transform = CGAffineTransformMakeRotation(-M_PI);

Step 2, rotate your raw cell 180deg in tableView:cellForRowAtIndexPath:

cell.transform = CGAffineTransformMakeRotation(M_PI);

Step 3, reverse your datasource. If you're using an NSMutableArray insert new objects at location 0 instead of using AddObject...

Now, the hard part is remembering that left is right and right is left only at the table level, so if you use

[tableView insertRowsAtIndexPaths:targetPath withRowAnimation:UITableViewRowAnimationLeft]

it now has to be

[tableView insertRowsAtIndexPaths:targetPath withRowAnimation:UITableViewRowAnimationRight]

and same for deletes, etc.

Depending on what your data store is you may have to handle that in reverse order as well...

Note: rotate the cells OPPOSITE the table, otherwise floating point innacuracy might cause the transform to get off perfect and you'll get crawlies on some graphics from time to time as you scroll... minor but annoying.

like image 51
ima747 Avatar answered Nov 13 '22 02:11

ima747


The accepted method introduces issues for my app - the scroll bar is on wrong side, and it mangles cell separators for UITableViewStyleGrouped

To fix this use the following

tableView.transform = CGAffineTransformMakeScale (1,-1);

and

cell.contentView.transform = CGAffineTransformMakeScale (1,-1);
// if you have an accessory view
cell.accessoryView.transform = CGAffineTransformMakeScale (1,-1); 
like image 40
Nick Hingston Avatar answered Nov 13 '22 00:11

Nick Hingston


Similar approach to ima747, but rotating 180 degrees also makes the scrolling indicator go to the opposite side. Instead I flipped the table view and its cells vertically.

self.tableView.transform = CGAffineTransformMakeScale(1, -1); //in viewDidLoad

cell.transform = CGAffineTransformMakeScale(1, -1);//in tableView:cellForRowAtIndexPath:
like image 17
Jeffrey Sun Avatar answered Nov 13 '22 02:11

Jeffrey Sun


Create a table header that is the height of the screen (in whatever orientation you are in) LESS the height of the of rows you have that you want visible. If there are no rows, then the header is the full height of the table view. As rows are added, simultaneously reduce the height of the table header by the height of the new row. This means changing the height of the frame of the view you provide for the table header. The point is to fill the space above the table rows to give the appearance that the rows are entering from the bottom. Using a table header (or section header) pushes the table data down. You can put whatever you like in the header view, even have it blank and transparent if you like.

This should have the effect you are looking for, I think.

Look at the attribute tableHeaderView. You simply set this to the view you want displayed in the table header. Then you can manipulate it as needed as you add rows. I can't recall just how forceful you then need to be to get the view to actually update in the UI. Might be as simple as calling setNeedsDisplay, if anything.

Alternatively, look at the methods tableView:viewForHeaderInSection: and tableView:heightForHeaderInSection:. Similar to using a table header view, you would want to have an instance variable that you setup once but that you can access from these methods to return either the view itself or its height, respectively. When you need to change the view for the (first) section, you can use reloadSections:withAnimation: to force an update to the view on screen after you have changed the views height (or content).

Any of that make sense? I hope so. :-)

like image 2
Mark Granoff Avatar answered Nov 13 '22 02:11

Mark Granoff