在UIScrollView中查找滚动方向?

Ale*_*987 176 iphone cocoa-touch uiscrollview ios

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");

    }

}
Run Code Online (Sandbox Code Playgroud)

但是当我移动时,这种方法有时根本不会被调用.你怎么看?

mem*_*ons 387

确定方向相当简单,但请记住,方向可以在手势过程中多次改变.例如,如果您有一个滚动视图,其中打开了分页并且用户滑动以转到下一页,则初始方向可能是向右的,但如果您启用了反弹,则它将暂时完全没有方向然后简单地向左走.

要确定方向,您需要使用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.    
}
Run Code Online (Sandbox Code Playgroud)

我正在使用以下枚举来定义方向.将第一个值设置为ScrollDirectionNone具有额外的好处,即在初始化变量时将该方向设置为默认值:

typedef NS_ENUM(NSInteger, ScrollDirection) {
    ScrollDirectionNone,
    ScrollDirectionRight,
    ScrollDirectionLeft,
    ScrollDirectionUp,
    ScrollDirectionDown,
    ScrollDirectionCrazy,
};
Run Code Online (Sandbox Code Playgroud)

  • @JosueEspinosa若要获取正确的滚动方向,请将其放在lastViewOffset setter调用的scrollViewWillBeginDragging:方法中。 (2认同)

fol*_*ben 72

...我想知道用户滚动的方向(左,右).

在这种情况下,在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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 可能是最好的解决方案,但在启动非常缓慢的情况下,dx 将等于 0。 (2认同)

Jus*_*ner 58

使用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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是贾斯汀的一个很好的补充,但是我想添加一个编辑.如果您的滚动视图启用了分页,并且您执行了最终返回其初始位置的拖动,则当前"其他"条件将认为"向左移动",即使它应该是"无变化". (3认同)

rou*_*nak 49

无需添加额外的变量来跟踪此情况.只要使用这样UIScrollViewpanGestureRecognizer属性.不幸的是,这仅在速度不为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");
}
Run Code Online (Sandbox Code Playgroud)

您可以使用x和y组件的组合来检测向上,向下,向左和向右.

  • 不幸的是,这只是在拖动时工作.移除触摸时,速度为0,即使在仍然滚动时也是如此. (8认同)

dav*_*lgr 39

解决方案

func scrollViewDidScroll(scrollView: UIScrollView) {
     if(scrollView.panGestureRecognizer.translationInView(scrollView.superview).y > 0)
     {
         print("up")
     }
    else
    {
         print("down")
    } 
}
Run Code Online (Sandbox Code Playgroud)

  • 尝试使用 `velocityInView` 而不是 `translationInView`。这解决了在同一运动中改变方向时出现的问题。 (3认同)
  • 这个解决方案非常完美.当我进入下一个屏幕并返回执行向上和向下滚动操作时,最常被接受的答案是无法工作. (2认同)

Ale*_*ano 17

斯威夫特4:

对于水平滚动,您可以简单地执行:

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

对于垂直滚动变化.x.y


Esq*_*uth 14

在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)

}
Run Code Online (Sandbox Code Playgroud)

我有一个动态视图,当用户滚动时更改位置,因此视图看起来像是停留在屏幕上的相同位置.我也在跟踪用户上升或下降的时间.

这也是另一种方式:

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    if targetContentOffset.memory.y < scrollView.contentOffset.y {
        println("Going up!")
    } else {
        println("Going down!")
    }
}
Run Code Online (Sandbox Code Playgroud)


Jav*_*ría 8

这是它对我有用的(在Objective-C中):

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

        NSString *direction = ([scrollView.panGestureRecognizer translationInView:scrollView.superview].y >0)?@"up":@"down";
        NSLog(@"%@",direction);
    }
Run Code Online (Sandbox Code Playgroud)


Ode*_*gev 7

- (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");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 当滚动视图的pagingEnabled属性的值为YES时,不会调用此方法. (2认同)

xu *_*nze 5

或者,可以观察关键路径"contentOffset".当您无法设置/更改滚动视图的委托时,这非常有用.

[yourScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
Run Code Online (Sandbox Code Playgroud)

添加观察者后,您现在可以:

- (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
    }
}
Run Code Online (Sandbox Code Playgroud)

请记得在需要时移除观察者.例如,你可以在添加观察者viewWillAppear中,并删除它viewWillDisappear


And*_*kov 5

这是我对@followben 回答中的行为的解决方案,但在缓慢启动时没有损失(当 dy 为 0 时)

@property (assign, nonatomic) BOOL isFinding;
@property (assign, nonatomic) CGFloat previousOffset;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    self.isFinding = YES;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (self.isFinding) {
        if (self.previousOffset == 0) {
            self.previousOffset = self.tableView.contentOffset.y;

        } else {
            CGFloat diff = self.tableView.contentOffset.y - self.previousOffset;
            if (diff != 0) {
                self.previousOffset = 0;
                self.isFinding = NO;

                if (diff > 0) {
                    // moved up
                } else {
                    // moved down
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Jav*_*ría 5

迅速地:

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0 {
        print("down")
    } else {
        print("up")
    }
}
Run Code Online (Sandbox Code Playgroud)

您也可以在scrollViewDidScroll中执行此操作。