UITableView with custom paging-like behaviour

2019-02-02 01:38发布

问题:

I am trying to implement paging for custom sized pages in the UITableView. What I am trying to achieve is to have the top of the active cell align with the top of the tableView, whilst still showing the top of the next cell at the bottom of the tableView (to incline the user to scroll and see more cells).

My cells are all of equal height.

If I set paging=YES this results in a slight offset that increases as I flick through the pages. This is due to my tableView being slightly taller than a single cell and the cell height/page size not aligning.

I have tried different things with paging enabled. I tried setting the size of the tableView to the height of the cell, but then turning off clipping and masking so the user could still see the next cell. This does not work as the next cell is only added to the underlying scrollView at the very last ms before the cell scrolls into the bounding box of the tableView.

I then started implementing the different scrollView delegate methods to mimic the paging behaviour - I can not seem to get it right.

I have, among other things, tried something like this:

- (void) scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    float cellHeight = [myCell rowHeight];
    int index = floorf(scrollView.contentOffset.y / cellHeight);

    *targetContentOffset = CGPointMake(targetContentOffset->x, targetContentOffset->y = (index * cellHeight));
}

While it sort of does the right thing, it behaves nothing like a scrollView/tableView with paging enabled.

I have found a few posts here from people trying to achieve the same thing, but the answers suffer from the same "non-native-snap-feel" that anything I tried myself does.

Thanks for any help given.

iOS >= 5.0

回答1:

Implement scrollViewWillEndDragging:withVelocity:targetContentOffset: to return top coordinate of the cell closest to targetContentOffset, not closest to your starting offset. The solution jjv360 provided does that well, but you might want to tweak it a bit depending on how high your cells are on average (jjv360's solution might be too snappy on really big cells).

I would just like to add that you can make UITableView's deceleration faster to behave more like paged UIScrollView by changing its decelerationRate property (just do it once in init/viewDidLoad/wherever).

self.tableView.decelerationRate = UIScrollViewDecelerationRateFast;


回答2:

If you turn off paging you can use the UIScrollView delegate function:

-(void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint*)targetContentOffset {

    // Get index path for target row
    NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:(*targetContentOffset)];

    // Set new target
    (*targetContentOffset) = [self.tableView rectForRowAtIndexPath:indexPath].origin;

}


回答3:

I solved this problem with this code:

- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {

    CGFloat pageWidth = self.collectionView.frame.size.width + 10 /* Optional Photo app like gap between images */;

    _currentPage = floor((self.collectionView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;

    NSLog(@"Dragging - You are now on page %i", _currentPage);
}

-(void) scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint*)targetContentOffset {

    CGFloat pageWidth = self.collectionView.frame.size.width + 10;

    int newPage = _currentPage;

    if (velocity.x == 0) // slow dragging not lifting finger
    {
        newPage = floor((targetContentOffset->x - pageWidth / 2) / pageWidth) + 1;
    }
    else
    {
        newPage = velocity.x > 0 ? _currentPage + 1 : _currentPage - 1;

        if (newPage < 0)
            newPage = 0;
        if (newPage > self.collectionView.contentSize.width / pageWidth)
            newPage = ceil(self.collectionView.contentSize.width / pageWidth) - 1.0;
    }

    NSLog(@"Dragging - You will be on %i page (from page %i)", newPage, _currentPage);

    *targetContentOffset = CGPointMake(newPage * pageWidth, targetContentOffset->y);
}

Thanks to http://www.mysamplecode.com/2012/12/ios-scrollview-example-with-paging.html for pointing the right way.