当用户在启用分页的UIScrollView中更改页面时,有没有办法检测或获取通知?
答案 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)
做到这一点并不容易:
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
}
}