I\'m facing with a simple but tedious problem. What I\'m trying to do is make an UITableView to page like an UIScrollView but enabling paging doesn\'t help me so much because I
Starting with k06a's answer, I've refined it a bit so it works more like the real paginated UITableView. The differences in behaviour are quite noticeable with full screen table rows. Even a mini-flick in either direction should scroll the table to the next page: I do this by checking velocity first.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
CGFloat rowHeight = tableView.rowHeight;
int verticalOffset = ((int)targetContentOffset->y % (int)rowHeight);
if (velocity.y < 0)
{
targetContentOffset->y -= verticalOffset;
}
else if (velocity.y > 0)
{
targetContentOffset->y += (rowHeight - verticalOffset);
}
// No velocity, snap to closest page
else
{
if (verticalOffset < rowHeight / 2)
{
targetContentOffset->y -= verticalOffset;
}
else
{
targetContentOffset->y += (rowHeight - verticalOffset);
}
}
}
Note that additionally setting
self.tableView.decelerationRate = UIScrollViewDecelerationRateFast;
in viewDidLoad:
makes it closer to the real thing, but not quite.
I've been fiddling with setting even faster deceleration rates using the code shown here but I couldn't get it right.
More simple and more efficient :)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if(decelerate) return;
[self scrollViewDidEndDecelerating:scrollView];
}
- (void)scrollViewDidEndDecelerating:(UITableView *)tableView {
[tableView scrollToRowAtIndexPath:[tableView indexPathForRowAtPoint: CGPointMake(tableView.contentOffset.x, tableView.contentOffset.y+tableView.rowHeight/2)] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
This works like real paging:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
int tomove = ((int)targetContentOffset->y % (int)self.tableView.rowHeight);
if(tomove < self.tableView.rowHeight/2)
targetContentOffset->y -= tomove;
else
targetContentOffset->y += (self.tableView.rowHeight-tomove);
}
and make this in -viewDidLoad
:
self.tableView.decelerationRate = UIScrollViewDecelerationRateFast;
Simple but efficient:
- (void)scrollViewDidEndDecelerating:(UITableView *)tableView {
int tomove = ((int)tableView.contentOffset.y%(int)tableView.rowHeight);
if(tomove < tableView.rowHeight/2) [tableView setContentOffset:CGPointMake(0, tableView.contentOffset.y-tomove) animated:YES];
else [tableView setContentOffset:CGPointMake(0, tableView.contentOffset.y+(tableView.rowHeight-tomove)) animated:YES];
}
- (void)scrollViewDidEndDragging:(UITableView *)scrollView willDecelerate:(BOOL)decelerate {
if(decelerate) return;
[self scrollViewDidEndDecelerating:scrollView];
}
And in Swift...
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.scrollViewDidEndDecelerating(scrollView)
}
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if let indexPathToScrollTo: NSIndexPath = self.tableView.indexPathForRowAtPoint(CGPointMake(self.tableView.contentOffset.x, self.tableView.contentOffset.y+tableView.rowHeight/2)) {
self.tableView.scrollToRowAtIndexPath(indexPathToScrollTo, atScrollPosition: UITableViewScrollPosition.Top, animated: true)
}
}