Как определить, когда UIScrollView завершил прокрутку - PullRequest
136 голосов
/ 14 июня 2009

UIScrollViewDelegate имеет два метода делегата scrollViewDidScroll: и scrollViewDidEndScrollingAnimation:, но ни один из них не сообщает вам, когда прокрутка завершена. scrollViewDidScroll только уведомляет вас о том, что прокрутка не прокручивалась, а не завершила прокрутку.

Другой метод scrollViewDidEndScrollingAnimation, похоже, срабатывает только в том случае, если вы программно перемещаете представление прокрутки, а не в том случае, если пользователь выполняет прокрутку.

Кто-нибудь знает схему обнаружения прокрутки в представлении прокрутки?

Ответы [ 17 ]

1 голос
/ 02 января 2017

Если кому-то нужно, вот ответ Эшли Смарт в Swift

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        NSObject.cancelPreviousPerformRequests(withTarget: self)
        perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), with: nil, afterDelay: 0.3)
    ...
}

func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        NSObject.cancelPreviousPerformRequests(withTarget: self)
    ...
}
1 голос
/ 16 ноября 2013

Подведем итоги (и для новичков). Это не так больно. Просто добавьте протокол, затем добавьте функции, необходимые для обнаружения.

В представлении (классе), содержащем UIScrolView, добавьте протокол, а затем добавьте все функции отсюда в ваше представление (класс).

// --------------------------------
// In the "h" file:
// --------------------------------
@interface myViewClass : UIViewController  <UIScrollViewDelegate> // <-- Adding the protocol here

// Scroll view
@property (nonatomic, retain) UIScrollView *myScrollView;
@property (nonatomic, assign) BOOL isScrolling;

// Protocol functions
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView;


// --------------------------------
// In the "m" file:
// --------------------------------
@implementation BlockerViewController

- (void)viewDidLoad {
    CGRect scrollRect = self.view.frame; // Same size as this view
    self.myScrollView = [[UIScrollView alloc] initWithFrame:scrollRect];
    self.myScrollView.delegate = self;
    self.myScrollView.contentSize = CGSizeMake(scrollRect.size.width, scrollRect.size.height);
    self.myScrollView.contentInset = UIEdgeInsetsMake(0.0,22.0,0.0,22.0);
    // Allow dragging button to display outside the boundaries
    self.myScrollView.clipsToBounds = NO;
    // Prevent buttons from activating scroller:
    self.myScrollView.canCancelContentTouches = NO;
    self.myScrollView.delaysContentTouches = NO;
    [self.myScrollView setBackgroundColor:[UIColor darkGrayColor]];
    [self.view addSubview:self.myScrollView];

    // Add stuff to scrollview
    UIImage *myImage = [UIImage imageNamed:@"foo.png"];
    [self.myScrollView addSubview:myImage];
}

// Protocol functions
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    NSLog(@"start drag");
    _isScrolling = YES;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    NSLog(@"end decel");
    _isScrolling = NO;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    NSLog(@"end dragging");
    if (!decelerate) {
       _isScrolling = NO;
    }
}

// All of the available functions are here:
// https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html
1 голос
/ 04 апреля 2014

У меня был случай касания и перетаскивания действий, и я обнаружил, что перетаскивание вызывало scrollViewDidEndDecelerating

И изменение смещения вручную с кодом ([_scrollView setContentOffset: contentOffset animated: YES];) вызывало scrollViewDidEndScrollingAnimation.

//This delegate method is called when the dragging scrolling happens, but no when the     tapping
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    //do whatever you want to happen when the scroll is done
}

//This delegate method is called when the tapping scrolling happens, but no when the  dragging
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
     //do whatever you want to happen when the scroll is done
}
1 голос
/ 26 октября 2017

Альтернативой может быть использование scrollViewWillEndDragging:withVelocity:targetContentOffset, которое вызывается всякий раз, когда пользователь поднимает палец, и содержит смещение целевого содержимого, в котором прокрутка останавливается. Использование этого смещения содержимого в scrollViewDidScroll: правильно определяет, когда представление прокрутки прекратило прокрутку.

private var targetY: CGFloat?
public func scrollViewWillEndDragging(_ scrollView: UIScrollView,
                                      withVelocity velocity: CGPoint,
                                      targetContentOffset: UnsafeMutablePointer<CGPoint>) {
       targetY = targetContentOffset.pointee.y
}
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (scrollView.contentOffset.y == targetY) {
        print("finished scrolling")
    }
0 голосов
/ 28 декабря 2018

Если вы в Rx, вы можете расширить UIScrollView следующим образом:

import RxSwift
import RxCocoa

extension Reactive where Base: UIScrollView {
    public var didEndScrolling: ControlEvent<Void> {
        let source = Observable
            .merge([base.rx.didEndDragging.map { !$0 },
                    base.rx.didEndDecelerating.mapTo(true)])
            .filter { $0 }
            .mapTo(())
        return ControlEvent(events: source)
    }
}

, что позволит вам сделать так:

scrollView.rx.didEndScrolling.subscribe(onNext: {
    // Do what needs to be done here
})

Это будет учитывать как перетаскивание, так и замедление.

0 голосов
/ 19 августа 2015

UIScrollview имеет метод делегата

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

Добавьте приведенные ниже строки кода в методе делегата

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGSize scrollview_content=scrollView.contentSize;
CGPoint scrollview_offset=scrollView.contentOffset;
CGFloat size=scrollview_content.width;
CGFloat x=scrollview_offset.x;
if ((size-self.view.frame.size.width)==x) {
    //You have reached last page
}
}
0 голосов
/ 10 марта 2017

Существует метод UIScrollViewDelegate, который можно использовать для обнаружения (или лучше сказать «предсказать»), когда прокрутка действительно завершена:

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)

из UIScrollViewDelegate, который можно использовать для обнаружения (или лучше сказать «предсказать»), когда прокрутка действительно завершена.

В моем случае я использовал его с горизонтальной прокруткой следующим образом (в Swift 3 ):

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    perform(#selector(self.actionOnFinishedScrolling), with: nil, afterDelay: Double(velocity.x))
}
func actionOnFinishedScrolling() {
    print("scrolling is finished")
    // do what you need
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...