iPhone Development: Force UITableView to show only complete cells
Tallymander uses UITableViewCells not only to display data but also to manipulate it. That means that partially-visible cells — that is, those that are cut off at the top or bottom of the view — aren’t terribly useful.
Better, I thought, would be to always ensure that when a partially-visible cell crops up, the UITableViewController will quietly nudge things to be completely visible.
In the first image, you can see the only part of the top and bottom cell. In the second image, the cells have been nudged so that everything visible is completely visible. This took a little noodling around with math but it wasn’t hard to do. Put this method into your UITableViewController subclass:
- (void)snapBottomCell { NSInteger cellHeight = 62; //Cells for my view are 62px tall. Sub your own height here NSInteger offsetOverage = (NSInteger) self.tableView.contentOffset.y % cellHeight; //Use the tableview's contentOffset property and the cell height to determine how much is being cut off if (offsetOverage > 0) { //If the overage is more than 0, we should figure out what the new offset needs to be NSInteger newOffset; if (offsetOverage >= (cellHeight/2)) { newOffset = self.tableView.contentOffset.y + (cellHeight - offsetOverage); //If the overage is greater than or equal to half the height of a cell, pull the cell up so it's fully visible } else { newOffset = self.tableView.contentOffset.y - offsetOverage; //Else, push the cell out of view } //With the new offset determined, animate the movement: [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.5]; [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; [self.tableView setContentOffset:CGPointMake(0, newOffset) animated:NO]; [UIView commitAnimations]; } }
You’ll need to implement these two delegate methods as well:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [self snapBottomCell]; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (decelerate == NO) { [self snapBottomCell]; } }
And that’s it. If more than half of the bottom cell is visible, the cell gets nudged completely into view. If less than half is visible, it’s pushed out of view.
You could change snapBottomCell to accept cellHeight as an argument if you need to accommodate cells with variable heights. You might sort out a particular cell’s height like so:
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:CGPointMake(0, (self.tableView.frame.size.height - 1))]; //Get the index path of the cell currently visible at the bottom edge of the tableview UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; [self snapBottomCell:cell.frame.size.height];
There are cases where this isn’t useful: long lists whose primary function is selecting data for loading in another view, for example. Still, any time you’re using UITableViewCells to house controls or chunky bits of data, it might be good to ensure that only whole cells are displayed.



