Gibt es eine Möglichkeit, eine Benachrichtigung zu erkennen oder zu erhalten, wenn der Benutzer die Seite in einer Paging-fähigen UIScrollView ändert?
Antworten:
Implementieren Sie den Delegaten von UIScrollView. Diese Methode ist genau das, wonach Sie suchen.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
Verwenden Sie diese Option, um festzustellen, welche Seite gerade angezeigt wird, und führen Sie beim Seitenwechsel eine Aktion aus:
- (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;
}
}
Wenn es für Sie akzeptabel ist, erst dann auf den Seitenwechsel zu reagieren, wenn der Bildlauf vollständig gestoppt ist, ist es am besten, die obigen Schritte innerhalb der scrollViewDidEndDecelerating:
Delegate-Methode anstelle der scrollViewDidScroll:
Methode auszuführen.
scrollViewDidEndDecelerating
ist eine bessere, aber keine vollständige Lösung. Ich habe eine eigene Lösung hinzugefügt, die das Problem für mich vollständig gelöst hat.
In der paging-fähigen Bildlaufansicht können Sie scrollViewDidEndDecelerating verwenden, um festzustellen , wann die Ansicht auf einer Seite festgelegt ist (möglicherweise dieselbe Seite).
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
scrollViewDidScroll
wird bei jeder Bewegung aufgerufen. Im Zusammenhang mit Paging kann die aktivierte Ansicht verwendet werden, um festzustellen, wann ein Bildlauf durchgeführt wurde, um zur nächsten Seite zu gelangen (wenn das Ziehen an diesem Punkt gestoppt wird).
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
und - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
überhaupt nicht aufgerufen werden?
Wie wäre es mit der Kombination von zwei Methoden von UIScrollViewDelegate?
In scrollViewDidEndDragging(_:willDecelerate:)
, wenn es sofort aufhört, machen wir die Seite Berechnung; Wenn es langsamer wird, lassen wir es los und es wird von gefangen scrollViewDidEndDecelerating(_:)
.
Der Code wird mit XCode Version 7.1.1, Swift Version 2.1 getestet
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
}
}
Das erste Ergebnis bei Google zur Seitenerkennung, daher musste ich dies meiner Meinung nach mit einer besseren Lösung beantworten. (Auch wenn diese Frage vor zweieinhalb Jahren gestellt wurde.)
Ich würde es vorziehen, nicht nur anzurufen scrollViewDidScroll
, um die Seitenzahl zu verfolgen. Das ist ein Overkill für so etwas Einfaches. Die Verwendung scrollViewDidEndDecelerating
funktioniert und stoppt auf einer Seite, ABER (und es ist ein großes, aber), wenn der Benutzer zweimal etwas schneller als normal über den Bildschirm wischt, scrollViewDidEndDecelerating
wird nur einmal aufgerufen. Sie können problemlos von Seite 1 zu Seite 3 wechseln, ohne Seite 2 zu verarbeiten.
Das hat es für mich komplett gelöst:
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
scrollView.userInteractionEnabled = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//Run your code on the current page
scrollView.userInteractionEnabled = YES;
}
Auf diese Weise kann der Benutzer jeweils nur eine Seite ohne das oben beschriebene Risiko streichen.
scrollViewWillBeginDecelerating
hineinstecken, werden Sie feststellen, dass der Benutzer in der Sekunde, in der der Benutzer seinen Finger vom ersten Wischen hebt, diesen Haltepunkt erreicht.
Swift 4
Ich fand den besten Weg, dies zu tun, ist mit scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)
. Sie können vorhersagen, ob Paging auftreten wird, sobald Sie Ihren Finger vom Bildschirm heben. Dieses Beispiel dient zum horizontalen Blättern.
Denken Sie daran, das scrollView.delegate
dem Objekt zuzuweisen , das UIScrollViewDelegate
diese Methode übernimmt und implementiert.
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)
}
Hier ist die schnelle Lösung dafür.
Machen Sie zwei Eigenschaften currentPage und previousPage in der Klasse, in der Sie Ihren Code implementieren, und initialisieren Sie sie mit 0.
Aktualisieren Sie jetzt currentPage von scrollViewDidEndDragging ( : willDecelerate :) und scrollViewDidEndDecelerating ( : scrollView :).
Und aktualisieren Sie dann die vorherige Seite in scrollViewDidEndScrollingAnimation (_: scrollView :)
//Class Properties
var currentPage = 0
var previousPage = 0
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
updatePage(scrollView)
return
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView){
updatePage(scrollView)
return
}
func updatePage(scrollView: UIScrollView) {
let pageWidth:CGFloat = scrollView.frame.width
let current:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
currentPage = Int(current)
if currentPage == 0 {
// DO SOMETHING
}
else if currentPage == 1{
// DO SOMETHING
}
}
func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
if previousPage != currentPage {
previousPage = currentPage
if currentPage == 0 {
//DO SOMETHING
}else if currentPage == 1 {
// DO SOMETHING
}
}
}
Das ist nicht so einfach:
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)
}
Funktioniert perfekt.
pageHasActuallyChanged
wird nur aufgerufen, wenn der Benutzer Seiten wechselt, was Menschen als "Seitenwechsel" betrachten würden.
Dies ist zum Zeitpunkt des Starts schwierig zu initialisieren und hängt davon ab, wie Sie das ausgelagerte System verwenden .
In jedem ausgelagerten System haben Sie höchstwahrscheinlich so etwas wie "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
}
}
Wenn der Benutzer das "Buch" auf Seite 17 öffnet, rufen Sie in Ihrer Bossklasse diese Funktion auf, um es beim Aufrufen auf "17" zu setzen.
In einem solchen Beispiel , würden Sie müssen nur daran denkendass Sie müssen zunächst unsere possibleQuantumPage Wert in solchen bringup Funktionen eingestellt; Es gibt keinen wirklich verallgemeinerten Weg, um mit der Ausgangssituation umzugehen.
Schließlich möchten Sie vielleicht nur "schnell" zur Startseite scrollen und wer weiß, was das in einer quantumPage-Situation "bedeutet". Stellen Sie daher sicher, dass Sie Ihr Quantenseitensystem während des Startvorgangs entsprechend Ihrer Situation sorgfältig initialisieren.
Kopieren Sie auf jeden Fall einfach die fünf Funktionen oben und fügen Sie sie ein, um ein perfektes Quanten-Paging zu erhalten.
Für 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
}
}
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)")
}
}
Und Erweiterung verwenden
extension UIScrollView {
var currentPage: Int {
return Int((self.contentOffset.x + (0.5 * self.frame.size.width)) /
self.frame.width) + 1
}
}