ユーザーがページング対応の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 を使用して、ビューがページに確定するタイミングを知ることができます(同じページである可能性があります)。
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
scrollViewDidScroll
はすべての動きで呼び出されます。また、ページングのコンテキストでは、ビューを使用して次のページに移動するのに十分なスクロールがあるかどうかを確認できます(その時点でドラッグが停止している場合)。
UIScrollViewDelegateの2つのメソッドを組み合わせてどうですか?
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
}
}
ページ検出のためのグーグルでの最初の結果なので、私の意見ではより良い解決策でこれに答えなければなりませんでした。 (この質問が2年半前に尋ねられたとしても。)
ページ番号を追跡するためだけにscrollViewDidScroll
を呼び出さないようにします。それはそれのような簡単な何かのための行き過ぎです。 scrollViewDidEndDecelerating
を使用すると動作し、ページの変更で停止します[〜#〜] but [〜#〜](そしてそれは大きいですが、 )ユーザーが通常よりも2倍速く画面をスワイプすると、scrollViewDidEndDecelerating
は1回だけ呼び出されます。ページ#2を処理せずに、ページ#1からページ#3に簡単に移動できます。
これは私にとって完全に解決しました:
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
scrollView.userInteractionEnabled = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//Run your code on the current page
scrollView.userInteractionEnabled = YES;
}
これにより、ユーザーは上記のリスクなしに一度に1ページだけスワイプできます。
Swift 4
これを行う最良の方法は、scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)
を使用することです。画面から指を離すとすぐにページングが発生するかどうかを予測できます。この例は、水平方向にページングするためのものです。
UIScrollViewDelegate
を採用し、このメソッドを実装するオブジェクトにscrollView.delegate
を割り当てることを忘れないでください。
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)
}
これがSwiftの解決策です。
コードを実装するクラスでcurrentPageとpreviousPageの2つのプロパティを作成し、0に初期化します。
ScrollViewDidEndDragging(:willDecelerate :)およびscrollViewDidEndDecelerating(:scrollView :)からcurrentPageを更新します。
そして、scrollViewDidEndScrollingAnimation(_:scrollView :)のpreviousPageを更新します
//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
}
}
}
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
}
}