【问题标题】:Custom UIScrollView paging with scrollViewWillEndDragging使用 scrollViewWillEndDragging 自定义 UIScrollView 分页
【发布时间】:2012-03-11 04:12:48
【问题描述】:

我正在尝试在 iOS 5 中使用新的 scrollViewWillEndDragging:withVelocity:targetContentOffset: UIScrollView 委托调用,但我似乎无法让它真正正确地响应我。我正在更改 targetContentOffset->x 值,但它永远不会被使用。我知道代码正在运行,因为它会在该函数中遇到断点。我什至尝试将偏移值设置为硬编码数字,这样我就知道它会在哪里结束,但它永远不会起作用。

有没有人能够正确使用它并使其工作?是否有任何其他必须实现的委托调用才能使其工作?

这是我的代码,以防有人发现它有问题:

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

【问题讨论】:

  • 您是否在此滚动视图中将pagingEnabled 设置为YES
  • pagingEnabled 设置为 NO,文档说它需要设置为 NO 才能调用此委托。我还尝试将其设置为 YES 只是为了踢球,它没有按照文档被调用,但是有一些控制台日志记录说不要在 pagingEnabled 设置为 YES 的情况下执行此操作。
  • 我的问题是我在运行 iOS4 的手机上测试它。另外,您是否设置了 UIScrollView 的委托属性?
  • 它不需要其他委托方法,你说得对,pagingEnabled 必须为 NO。您确定此代码不起作用吗?您没有提到真正的测试是什么:在 didScroll 委托方法中,您应该 NSLog contentOffset 那里。触发此方法后,查看 contentOffset 是否与您记录为 pagedX 的那个不一致。

标签: ios uiscrollview uikit uiscrollviewdelegate


【解决方案1】:

您可以使用以下代码实现自定义分页:

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

当然你必须设置 pagingEnabled = NO。 _currentPage 是一个类 iVar。 感谢http://www.mysamplecode.com/2012/12/ios-scrollview-example-with-paging.html 指出正确的方式。

【讨论】:

  • 这是迄今为止我发现的模拟默认实现的最佳解决方案(一次只滚动一页,处理慢速拖动等)
  • 这行得通,但是如果拖动以太小的速度结束,它将向新页面移动太慢。有关如何解决此问题的任何建议?
  • 要回答我自己的问题,设置 self.scrollView.decelerationRate = UIScrollViewDecelerationRateFast 会很棒! :)
  • 像魅力一样工作。尝试多次对其进行投票。但它不会让我。感谢您的精彩回答。谢谢。
  • 完美运行。谢谢。
【解决方案2】:

SWIFT 3

这里有一个演示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
}

【讨论】:

  • 值得注意的是,如果你有一个top inset或者left inset,需要在赋值前加上点值。
【解决方案3】:

我能够运行一个快速测试并让它正确触发并让我的对象根据需要停止。我使用以下简单测试做到了这一点:

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

似乎这种方法可能不是您代码中的问题,但更有可能是您的“goodOffsetX”没有正确计算要停止的有效值。

【讨论】:

    【解决方案4】:

    斯威夫特 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)
        }
    }
    

    我还按照@skagedal 的建议使用了collectionView?.decelerationRate = UIScrollViewDecelerationRateFast 来提高页面速度。

    【讨论】:

      【解决方案5】:
      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
       }
      

      【讨论】:

        猜你喜欢
        • 2017-05-20
        • 1970-01-01
        • 2011-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多