Custom UIScrollView paging with scrollViewWillEndD

2019-01-30 08:54发布

I'm trying to use the new scrollViewWillEndDragging:withVelocity:targetContentOffset: UIScrollView delegate call in iOS 5 but i can't seem to get it to actually respond to me correctly. I'm changing the targetContentOffset->x value but it never ends up being used. I know the code is being ran because it'll hit breakpoints in that function. I've even tried setting the offset value to a hard coded number so i'd know where it would end up but it never works.

Has anyone been able to use this correctly and make it work? Is there any other delegate call that must be implemented in order for this to work?

Here's my code in case someone sees something wrong with it:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    // goodOffsetX returns the contentOffset i want the scrollView to stop at
    CGFloat goodOffsetX = [self _horizontalContentOffsetForTargetHorizontalContentOffset:(*targetContentOffset).x velocity:velocity.x];

    NSLog( @" " );
    NSLog( @"scrollViewWillEndDragging" );
    NSLog( @"   velocity: %f", velocity.x );
    NSLog( @"   currentX: %f", scrollView.contentOffset.x );
    NSLog( @"   uikit targetX: %f", (*targetContentOffset).x );
    NSLog( @"   pagedX: %f", goodOffsetX );

    targetContentOffset->x = goodOffsetX; 
}

5条回答
2楼-- · 2019-01-30 09:19

Swift 2.2:

extension SomeCollectionViewController {

    override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
        let pageWidth = Float(collectionView!.frame.size.width)
        let xCurrentOffset = Float(collectionView!.contentOffset.x)
        currentPage = floor((xCurrentOffset - pageWidth / 2) / pageWidth) + 1
    }

    override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        let pageWidth = Float(collectionView!.frame.size.width)
        let targetXContentOffset = Float(targetContentOffset.memory.x)
        let contentWidth = Float(collectionView!.contentSize.width)

        var newPage = currentPage
        if velocity.x == 0 {
            newPage = floor((targetXContentOffset - pageWidth / 2) / pageWidth) + 1
        } else {
            newPage = velocity.x > 0 ? currentPage + 1 : currentPage - 1
            if newPage < 0 {
                newPage = 0
            }
            if newPage > contentWidth / pageWidth {
                newPage = ceil(contentWidth / pageWidth) - 1.0
            }
        }
        targetContentOffset.memory.x = CGFloat(newPage * pageWidth)
    }
}

I also used the collectionView?.decelerationRate = UIScrollViewDecelerationRateFast as suggested by @skagedal to improve page speed.

查看更多
我想做一个坏孩纸
3楼-- · 2019-01-30 09:24

I was able to run a quick test and got this to correctly fire and make my object stop as desired. I did this using the following simple test:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
     targetContentOffset->x = scrollView.contentOffset.x - 10;    
}

It seems that this method is likely not the issue in your code, but it is more likely that your 'goodOffsetX' is not correctly calculating a valid value to stop at.

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-01-30 09:25

SWIFT 3

With a demo here https://github.com/damienromito/CollectionViewCustom

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    let pageWidth = Float(itemWidth + itemSpacing)
    let targetXContentOffset = Float(targetContentOffset.pointee.x)
    let contentWidth = Float(collectionView!.contentSize.width  )
    var newPage = Float(self.pageControl.currentPage)

    if velocity.x == 0 {
        newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0
    } else {
        newPage = Float(velocity.x > 0 ? self.pageControl.currentPage + 1 : self.pageControl.currentPage - 1)
        if newPage < 0 {
            newPage = 0
        }
        if (newPage > contentWidth / pageWidth) {
            newPage = ceil(contentWidth / pageWidth) - 1.0
        }
    }
    let point = CGPoint (x: CGFloat(newPage * pageWidth), y: targetContentOffset.pointee.y)
    targetContentOffset.pointee = point
}
查看更多
走好不送
5楼-- · 2019-01-30 09:32
public func scrollViewWillEndDragging(_ scrollView: UIScrollView ,withVelocity velocity: CGPoint, targetContentOffset: 
UnsafeMutablePointer<CGPoint>){  

let pageWidth = Float(appWidth + itemSpacing)
    let targetXContentOffset = Float(targetContentOffset.pointee.x)
    var newPage = Float(currentPageIndex)

    // I use this way calculate newPage:
    newPage = roundf(targetXContentOffset / pageWidth);

    //if velocity.x == 0 {
    //    newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0
    //} else {
    //    newPage = Float(velocity.x > 0 ? newPage + 1 : newPage - 1)
    //    if newPage < 0 {
    //        newPage = 0
    //    }
    //    if (newPage > contentWidth / pageWidth) {
    //        newPage = ceil(contentWidth / pageWidth) - 1.0
    //   }
    //}

    let targetOffsetX = CGFloat(newPage * pageWidth)
    let point = CGPoint (x: targetOffsetX, y: targetContentOffset.pointee.y)
    targetContentOffset.pointee = point
 }
查看更多
在下西门庆
6楼-- · 2019-01-30 09:36

You can implement custom paging with this code:

- (float) pageWidth {
    return ((UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout).itemSize.width +
    ((UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout).minimumInteritemSpacing;
}

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

    CGFloat pageWidth = self.collectionView.frame.size.width + 10 /* Optional Photo app like gap between images. Or use [self pageWidth] in case if you want the next page be also visible */;

    _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; // [self pageWidth]

    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);
}

Of course you must set pagingEnabled = NO. _currentPage is a class iVar. Thanks to http://www.mysamplecode.com/2012/12/ios-scrollview-example-with-paging.html for pointing the right way.

查看更多
登录 后发表回答