检测UIScrollView页面更改

Pom*_*air 77 iphone objective-c uiscrollview uiscrollviewdelegate ipad

当用户在启用分页的UIScrollView中更改页面时,有没有办法检测或获取通知?

Mic*_*all 192

使用此选项可以检测当前正在显示的页面,并对页面更改执行某些操作:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    static NSInteger previousPage = 0;
    CGFloat pageWidth = scrollView.frame.size.width;
    float fractionalPage = scrollView.contentOffset.x / pageWidth;
    NSInteger page = lround(fractionalPage);
    if (previousPage != page) {
        // Page has changed, do your thing!
        // ...
        // Finally, update previous page
        previousPage = page;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果滚动完全停止后只对页面更改做出反应是可以接受的,那么最好在scrollViewDidEndDecelerating:委托方法而不是scrollViewDidScroll:方法中执行上述操作.

  • 我知道这是旧的但也许它会有所帮助,使用这种方法可以返回负数以及超出scrollview边界的页面.如果您使用该页面访问阵列,这显然会导致问题,因此可能需要在页面上进行检查. (4认同)
  • 在里面写这个代码会好得多...... - (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView (2认同)

小智 64

在分页启用滚动视图中,您可以使用scrollViewDidEndDecelerating来了解视图何时在页面上结算(可能是同一页面).

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
Run Code Online (Sandbox Code Playgroud)

scrollViewDidScroll每次运动都会被召唤 并且在分页启用的上下文中,可以使用查看它何时滚动到足以移动到下一页(如果在该点停止拖动).

  • 这个解决方案有一个问题:如果用户在页面的末尾停止滚动(这是很有可能的),这个函数将不会被调用! (2认同)

Cul*_*SUN 36

如何组合UIScrollViewDelegate的两个方法?

scrollViewDidEndDragging(_:willDecelerate:),如果它立即停止,我们进行页面计算; 如果它正在减速,我们放手它就会被它抓住scrollViewDidEndDecelerating(_:).

该代码使用XCode版本7.1.1,Swift版本2.1进行测试

class ViewController: UIViewController, UIScrollViewDelegate {

  // MARK: UIScrollViewDelegate
  func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if decelerate == false {
        let currentPage = scrollView.currentPage
        // Do something with your page update
        print("scrollViewDidEndDragging: \(currentPage)")
    }
  }

  func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    let currentPage = scrollView.currentPage
    // Do something with your page update
    print("scrollViewDidEndDecelerating: \(currentPage)")
  }

}

extension UIScrollView {
   var currentPage: Int {
      return Int((self.contentOffset.x+ (0.5*self.frame.size.width))/self.frame.width)+1
   }
}
Run Code Online (Sandbox Code Playgroud)


Seg*_*gev 22

谷歌检测页面的第一个结果,所以我不得不在我看来用更好的解决方案回答这个问题.(即使2年半前问过这个问题.)

我不想打电话scrollViewDidScroll来跟踪页码.对于那些简单的东西来说,这太过分了.如果用户在屏幕上滑动两次比平常更快一次,则使用scrollViewDidEndDecelerating确实工作并停止在页面上更改但是它很大但是它很大scrollViewDidEndDecelerating.您可以轻松地从第1页到第3页,而无需处理第2页.

这完全解决了我:

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
    scrollView.userInteractionEnabled = NO;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    //Run your code on the current page
    scrollView.userInteractionEnabled = YES;
}
Run Code Online (Sandbox Code Playgroud)

这样,用户一次只能刷一页,而没有上述风险.

  • 如果用户尝试快速连续滑动多个页面,它将无法按预期运行.然而,虽然这并不完美,但在我有更多时间投入更好的解决方案之前,它是一个快速解决方案. (2认同)
  • 我知道,但是如果您在第一次滑动动画完成之前再次滑动,那么第二次滑动就会丢失. (2认同)

Vir*_*raj 17

实现UIScrollView的委托.这个方法正是你要找的.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
Run Code Online (Sandbox Code Playgroud)

  • 检测此方法中的页面切换效率不高,因为每次用户滑动时都会运行代码.因此最好在scrollViewDidEndDecelerating方法中执行此操作. (26认同)
  • @jianpx - 这个解决方案有一个问题:如果用户完全停止在页面末尾滚动(这很可能),则不会调用此函数! (2认同)

Dou*_*nte 11

斯威夫特4

我发现最好的方法是使用scrollViewWillEndDragging(_:withVelocity:targetContentOffset:).它可以让您预测一旦将手指从屏幕上移开就会发生分页.此示例用于水平分页.

请记住将其分配给scrollView.delegate采用的对象UIScrollViewDelegate并实现此方法.

var previousPageXOffset: CGFloat = 0.0

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

    let targetOffset = targetContentOffset.pointee

    if targetOffset.x == previousPageXOffset {
        // page will not change
    } else if targetOffset.x < previousPageXOffset {
        // scroll view will page left
    } else if targetOffset.x > previousPageXOffset {
        // scroll view will page right
    }

    previousPageXOffset = targetOffset.x
    // If you want to track the index of the page you are on just just divide the previousPageXOffset by the scrollView width.
    // let index = Int(previousPageXOffset / scrollView.frame.width)


}
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的答案,即使scrollView没有足够滚动来触发分页更改,也会调用其他方法. (2认同)