Чи є спосіб виявити або отримати сповіщення, коли користувач змінює сторінку в UIScrollView із підтримкою підкачки?
Відповіді:
Реалізуйте делегат UIScrollView. Цей метод - це те, що ви шукаєте.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
Використовуйте це, щоб визначити, яка сторінка зараз відображається, і виконати певні дії щодо зміни сторінки:
- (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:
методу.
scrollViewDidEndDecelerating
є кращим рішенням, але не повним. Я додав власне рішення, яке вирішило його повністю для мене.
У режимі прокрутки з увімкненим підкачуванням ви можете використовувати scrollViewDidEndDecelerating, щоб знати, коли подання осідає на сторінці (може бути на тій самій сторінці).
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
scrollViewDidScroll
викликається при кожному русі. А в контексті перегляду сторінок з увімкненим сторінком можна використовувати, щоб знайти, коли воно прокручене досить, щоб перейти на наступну сторінку (якщо перетягування зупинено в цьому місці).
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
і - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
не називається взагалі?
Як щодо поєднання двох методів 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
}
}
Перший результат на Google для виявлення сторінок, тому мені довелося відповісти на це кращим рішенням, на мій погляд. (навіть якщо це питання було задано 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;
}
Таким чином, користувач може прокручувати лише одну сторінку за раз без ризику, описаного вище.
scrollViewWillBeginDecelerating
і ви дізнаєтесь, що за секунду користувач піднімає палець від першого проведення, коли ви досягнете цієї точки розриву.
Стрімкий 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)
}
Ось швидке рішення для цього.
Зробіть дві властивості currentPage і previousPage у класі, де ви реалізуєте свій код, та ініціалізуйте їх до 0.
Тепер оновіть currentPage з scrollViewDidEndDragging ( : willDecelerate :) і scrollViewDidEndDecelerating ( : scrollView :).
А потім оновіть previousPage у 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
}
}
}
Зробити це не так просто:
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. Тож обов’язково обережно ініціалізуйте свою систему квантових сторінок під час підведення, виходячи з вашої ситуації.
У будь-якому випадку просто скопіюйте та вставте п’ять функцій зверху, щоб отримати ідеальну квантову сторінку.
Для Свіфта
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)")
}
}
І використовувати розширення
extension UIScrollView {
var currentPage: Int {
return Int((self.contentOffset.x + (0.5 * self.frame.size.width)) /
self.frame.width) + 1
}
}