检测UIScrollView页面更改

时间:2011-03-11 11:18:30

标签: iphone objective-c ipad uiscrollview uiscrollviewdelegate

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

10 个答案:

答案 0 :(得分: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;
    }
}

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

答案 1 :(得分:63)

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

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
每次运动都会调用{p> scrollViewDidScroll。在启用分页的上下文中,可以使用它来查找何时滚动到足以移动到下一页(如果在该点停止拖动)。

答案 2 :(得分:33)

如何组合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
   }
}

答案 3 :(得分:21)

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

我不想仅仅为跟踪页码而致电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;
}

这样,用户一次只能刷一页,而不会有上述风险。

答案 4 :(得分:18)

实现UIScrollView的委托。 This方法就是你要找的方法。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

答案 5 :(得分:8)

Swift 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)


}

答案 6 :(得分:1)

这是快速解决方案。

在要实现代码的类中创建两个属性currentPage和previousPage,并将它们初始化为0。

现在从scrollViewDidEndDragging(:willDecelerate :)更新currentPage 和scrollViewDidEndDecelerating(:scrollView :)。

然后在scrollViewDidEndScrollingAnimation(_:scrollView :)中更新previousPage

{{1}}

答案 7 :(得分:0)

  

对于Swift

static var previousPage: Int = 0
func scrollViewDidScroll(_ scrollView: UIScrollView){
let pageWidth: CGFloat = scrollView.frame.width
let fractionalPage: CGFloat = scrollView.contentOffset.x / pageWidth
let page = lround(Double(fractionalPage))
if page != previousPage
{
  print(page)
  // page changed
}
}

答案 8 :(得分:0)

剪切并粘贴2019

做到这一点并不容易:

var quantumPage: Int = -100 {   // the UNIQUELY LANDED ON, NEVER REPEATING page
    didSet {
        print(">>>>>> QUANTUM PAGE IS \(quantumPage)")
        pageHasActuallyChanged() // your function
    }
}

private var possibleQuantumPage: Int = -100 {
    didSet {
        if oldValue != possibleQuantumPage {
            quantumPage = possibleQuantumPage
        }
    }
}

public func scrollViewDidEndDragging(
                    _ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if decelerate == false {
        possibleQuantumPage = currentPageEvenIfInBetween
    }
}

public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    possibleQuantumPage = currentPageEvenIfInBetween
}

var currentPageEvenIfInBetween: Int {
   return Int((self.contentOffset.x + (0.5 * self.frame.width)) / self.frame.width)
}

完美运行。

当用户以人们认为“正在更改页面”的方式更改页面时,将仅 被调用。

pageHasActuallyChanged

这很难在启动时进行初始化,这取决于您使用分页系统的方式。

在任何分页系统中,您很可能会遇到类似“ scrollToViewAtIndex ...”的内容

open func scrollToViewAtIndexForBringup(_ index: Int) {
    if index > -1 && index < childViews.count {

        let w = self.frame.size.width
        let h = self.frame.size.height

        let frame = CGRect(x: CGFloat(index)*w, y: 0, width: w, height: h)
        scrollRectToVisible(frame, animated: false) // NOTE THE FALSE

        // AND IMPORTANTLY:
        possibleQuantumPage = currentPageEvenIfInBetween
    }
}

因此,如果用户在第17页上打开“书”,则在老板类中,您将调用该函数以在启动时将其设置为“ 17”。在这样的示例中,您只需要记住,必须首先在任何此类调用函数中设置我们可能的QuantumPage值。没有真正通用的方法来处理开始情况。毕竟,举例来说,您可能想要“快速滚动”到弹出页面,并且谁知道在QuantumPage情况下“意味着”什么,因此,只需根据您的情况仔细地初始化您的量子页面系统。

无论如何,只需将五个函数复制并粘贴到顶部即可获得完美的量子分页。

答案 9 :(得分:0)

var scrollViewPage = 0
override func viewDidLoad() {
    super.viewDidLoad()
    scrollViewPage = scrollView.currentPage
}

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

并使用扩展名

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