Находить направление прокрутки в UIScrollView? - PullRequest
174 голосов
/ 30 марта 2010

У меня есть UIScrollView только с горизонтальной прокруткой, и я хотел бы знать, в каком направлении (влево, вправо) пользователь прокручивает. Я подкласс UIScrollView переопределил метод touchesMoved:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];

    UITouch *touch = [touches anyObject];
    float now = [touch locationInView:self].x;
    float before = [touch previousLocationInView:self].x;
    NSLog(@"%f %f", before, now);
    if (now > before){
        right = NO;
        NSLog(@"LEFT");
    }
    else{
        right = YES;
        NSLog(@"RIGHT");

    }

}

Но этот метод иногда вообще не вызывается, когда я двигаюсь. Что ты думаешь?

Ответы [ 21 ]

384 голосов
/ 02 ноября 2010

Определение направления довольно просто, но имейте в виду, что направление может изменяться несколько раз в течение жеста. Например, если у вас есть представление прокрутки с включенной подкачкой и пользователь проводит пальцем, чтобы перейти на следующую страницу, начальное направление может быть вправо, но если у вас включен отскок, он на короткое время вообще не будет двигаться и затем кратко двигайтесь влево.

Чтобы определить направление, вам нужно использовать делегат UIScrollView scrollViewDidScroll. В этом примере я создал переменную с именем lastContentOffset, которую я использую для сравнения текущего смещения содержимого с предыдущим. Если оно больше, то scrollView прокручивается вправо. Если это меньше, тогда scrollView прокручивает влево:

// somewhere in the private class extension
@property (nonatomic, assign) CGFloat lastContentOffset;

// somewhere in the class implementation
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    ScrollDirection scrollDirection;

    if (self.lastContentOffset > scrollView.contentOffset.x) {
        scrollDirection = ScrollDirectionRight;
    } else if (self.lastContentOffset < scrollView.contentOffset.x) {
        scrollDirection = ScrollDirectionLeft;
    }

    self.lastContentOffset = scrollView.contentOffset.x;

    // do whatever you need to with scrollDirection here.    
}

Я использую следующее перечисление для определения направления. Установка первого значения в ScrollDirectionNone имеет дополнительное преимущество, заключающееся в том, что при инициализации переменных это направление является значением по умолчанию:

typedef NS_ENUM(NSInteger, ScrollDirection) {
    ScrollDirectionNone,
    ScrollDirectionRight,
    ScrollDirectionLeft,
    ScrollDirectionUp,
    ScrollDirectionDown,
    ScrollDirectionCrazy,
};
73 голосов
/ 16 февраля 2014

... Я хотел бы знать, в каком направлении (влево, вправо) пользователь прокручивает.

В этом случае на iOS 5 и выше используйте UIScrollViewDelegate, чтобы определить направление жеста панорамирования пользователя:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{ 
    if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0) {
        // handle dragging to the right
    } else {
        // handle dragging to the left
    }
}
57 голосов
/ 09 февраля 2012

Использование scrollViewDidScroll: - хороший способ найти текущее направление.

Если вы хотите узнать направление после , когда пользователь закончил прокрутку, используйте следующее:

@property (nonatomic) CGFloat lastContentOffset;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {

    self.lastContentOffset = scrollView.contentOffset.x;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

    if (self.lastContentOffset < scrollView.contentOffset.x) {
        // moved right
    } else if (self.lastContentOffset > scrollView.contentOffset.x) {
        // moved left
    } else {
        // didn't move
    }
}
49 голосов
/ 04 октября 2014

Нет необходимости добавлять дополнительную переменную, чтобы отслеживать это. Просто используйте свойство UIScrollView panGestureRecognizer, как это. К сожалению, это работает, только если скорость не равна 0:

CGFloat yVelocity = [scrollView.panGestureRecognizer velocityInView:scrollView].y;
if (yVelocity < 0) {
    NSLog(@"Up");
} else if (yVelocity > 0) {
    NSLog(@"Down");
} else {
    NSLog(@"Can't determine direction as velocity is 0");
}

Вы можете использовать комбинацию компонентов x и y для обнаружения вверх, вниз, влево и вправо.

33 голосов
/ 05 февраля 2016

Решение

func scrollViewDidScroll(scrollView: UIScrollView) {
     if(scrollView.panGestureRecognizer.translationInView(scrollView.superview).y > 0)
     {
         print("up")
     }
    else
    {
         print("down")
    } 
}
14 голосов
/ 30 декабря 2014

В iOS8 Swift я использовал этот метод:

override func scrollViewDidScroll(scrollView: UIScrollView){

    var frame: CGRect = self.photoButton.frame
    var currentLocation = scrollView.contentOffset.y

    if frame.origin.y > currentLocation{
        println("Going up!")
    }else if frame.origin.y < currentLocation{
        println("Going down!")
    }

    frame.origin.y = scrollView.contentOffset.y + scrollHeight
    photoButton.frame = frame
    view.bringSubviewToFront(photoButton)

}

У меня есть динамическое представление, которое меняет местоположения при прокрутке пользователя, поэтому представление может показаться, что оно осталось на том же месте на экране. Я также отслеживаю, когда пользователь идет вверх или вниз.

Вот и альтернативный способ:

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    if targetContentOffset.memory.y < scrollView.contentOffset.y {
        println("Going up!")
    } else {
        println("Going down!")
    }
}
12 голосов
/ 28 января 2018

Swift 4:

Для горизонтальной прокрутки вы можете просто сделать:

if scrollView.panGestureRecognizer.translation(in: scrollView.superview).x > 0 {
   print("left")
} else {
   print("right")
}

Для изменения вертикальной прокрутки .x с .y

8 голосов
/ 05 июля 2016

Вот что у меня сработало (в Objective-C):

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView{

        NSString *direction = ([scrollView.panGestureRecognizer translationInView:scrollView.superview].y >0)?@"up":@"down";
        NSLog(@"%@",direction);
    }
7 голосов
/ 01 февраля 2013
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {

    CGPoint targetPoint = *targetContentOffset;
    CGPoint currentPoint = scrollView.contentOffset;

    if (targetPoint.y > currentPoint.y) {
        NSLog(@"up");
    }
    else {
        NSLog(@"down");
    }
}
5 голосов
/ 06 июня 2013

В качестве альтернативы можно наблюдать путь ключа «contentOffset». Это полезно, когда невозможно установить / изменить делегата представления прокрутки.

[yourScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

После добавления наблюдателя вы можете теперь:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    CGFloat newOffset = [[change objectForKey:@"new"] CGPointValue].y;
    CGFloat oldOffset = [[change objectForKey:@"old"] CGPointValue].y;
    CGFloat diff = newOffset - oldOffset;
    if (diff < 0 ) { //scrolling down
        // do something
    }
}

Не забудьте удалить наблюдателя при необходимости. например Вы можете добавить наблюдателя в viewWillAppear и удалить его в viewWillDisappear

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