Wykrywanie zmiany strony UIScrollView

Czy istnieje sposób na wykrycie lub otrzymanie powiadomienia, gdy użytkownik zmienia stronę w uiscrollview z obsługą stronicowania?

Author: Michael Waterfall, 2011-03-11

10 answers

Zaimplementuj delegata UIScrollView. ta metoda jest tym, czego szukasz.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
 17
Author: Viraj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-11 11:20:25

Użyj tego, aby wykryć, która strona jest aktualnie wyświetlana i wykonać pewną akcję przy zmianie Strony:

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

Jeśli akceptowalne jest reagowanie na zmianę strony dopiero po całkowitym zatrzymaniu przewijania, najlepiej byłoby wykonać powyższe czynności wewnątrz metody delegowania scrollViewDidEndDecelerating: zamiast metody scrollViewDidScroll:.

 193
Author: Michael Waterfall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-01 09:25:37

W paging enabled scroll view możesz użyć scrollViewDidEndDecelerating, aby wiedzieć, kiedy widok jest rozliczany na stronie (może to być ta sama strona).

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

scrollViewDidScroll jest wzywany na każdy ruch. A w kontekście stronicowania włączony Widok może być używany do znalezienia, kiedy jest przewijany na tyle, aby przejść do następnej strony (jeśli przeciąganie jest zatrzymane w tym momencie).

 65
Author: Ankur Badola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-07 16:01:55

Jak o połączeniu dwóch metod UIScrollViewDelegate?

W scrollViewDidEndDragging(_:willDecelerate:), jeśli zatrzyma się od razu, wykonujemy obliczenia strony; jeśli zwalnia, odpuszczamy go i zostanie złapany przez scrollViewDidEndDecelerating(_:).

Kod jest testowany z Xcode w wersji 7.1.1, Swift w wersji 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
   }
}
 42
Author: Cullen SUN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-26 17:16:02

Pierwszy wynik w google dla wykrywania strony, więc musiałem odpowiedzieć na to lepszym rozwiązaniem moim zdaniem. (nawet jeśli pytanie to zostało zadane 2 i pół roku temu.)

Wolałbym nie dzwonić, żeby śledzić numer strony. To przesada dla czegoś prostego. Użycie scrollViewDidEndDecelerating działa i zatrzymuje się na zmianie Strony ale (i to duże ale) jeśli użytkownik przesunie palcem po ekranie dwa razy nieco szybciej niż normalnie scrollViewDidEndDecelerating zostanie wywołany tylko raz. Możesz łatwo przejść od strona # 1 do strony #3 bez przetwarzania strony # 2.

To rozwiązało to całkowicie dla mnie:

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

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

W ten sposób użytkownik może przesuwać tylko jedną stronę na raz bez ryzyka opisanego powyżej.

 24
Author: Segev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-20 13:04:27

Swift 4

Uznałem, że najlepszym sposobem na to jest użycie scrollViewWillEndDragging(_:withVelocity:targetContentOffset:). Pozwala przewidzieć, czy stronicowanie pojawi się zaraz po uniesieniu palca z ekranu. Ten przykład dotyczy stronicowania poziomego.

Pamiętaj o przypisaniu {[2] } do obiektu, który przyjmuje UIScrollViewDelegate i implementuje tę metodę.

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)


}
 18
Author: Doug Galante,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-27 17:54:11

Oto szybkie rozwiązanie tego problemu.

Utwórz dwie właściwości currentPage i previousPage w klasie, w której implementujesz kod i zainicjalizuj je na 0.

Teraz zaktualizuj currentPage z scrollViewDidEndDragging (: willDecelerate:) i scrollViewDidEndDecelerating (: scrollView:).

A następnie zaktualizuj previousPage w 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
           }
       }
   }
 2
Author: Rohit tomar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-22 10:25:00

Wytnij i wklej na rok 2019]}

Nie jest tak łatwo to zrobić:

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)
}
Działa idealnie.

pageHasActuallyChanged Wola tylko być wywołane, gdy użytkownik zmienia strony w tym, co ludzie uważają za "zmienianie stron".

Bądź świadomy: bringup jest trudny:

To jest trudne do zainicjowania w czasie bringup, a to zależy od tego, jak używasz systemu paged .

W każdym systemie paged najprawdopodobniej będziesz miał coś takiego "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
    }
}

Więc, jeśli użytkownik otworzy "książkę" na stronie 17, w klasie szefa będziesz wywoływał tę funkcję, aby ustawić ją na" 17 " przy bringup.

W takim przykładzie, musisz tylko pamiętać, że musi Ustaw wstępnie naszą możliwą wartość quantumpage w takich funkcjach bringup; nie ma naprawdę uogólnionego sposobu na poradzenie sobie z sytuacją początkową.

W końcu możesz, na przykład, chclno aby "szybko przewijać" do strony bringup, a kto wie, co to "oznacza" w sytuacji quantumPage. Pamiętaj więc, aby starannie zainicjować swój system stron kwantowych podczas bringup, w oparciu o swoją sytuację.

W każdym razie, po prostu skopiuj i wklej pięć funkcji na górze, aby uzyskać doskonałe przywoływanie kwantowe.

 1
Author: Fattie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Dla 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
    }
}
 0
Author: Hiren Panchal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-08 14:09:02
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)")
    }
}

I użyj rozszerzenia

extension UIScrollView {
    var currentPage: Int {
        return Int((self.contentOffset.x + (0.5 * self.frame.size.width)) / 
        self.frame.width) + 1
    }
}
 0
Author: Saad Tahir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-11 10:28:54