iOS:用于平滑滚动和轻弹视图的手势识别器

Posted

技术标签:

【中文标题】iOS:用于平滑滚动和轻弹视图的手势识别器【英文标题】:iOS: Gesture recogniser for smooth scrolling and flicking a View 【发布时间】:2012-10-12 08:22:58 【问题描述】:

我正在构建一个 iPad 应用程序,我需要在其中允许使用两个视图之间提供的分隔视图来调整视图大小。分隔视图只是两个半屏内容视图之间的 20 像素高度视图 - 请参阅附加图像。

当用户向上或向下滚动此分隔视图时,两个内容视图都会相应地更改其大小。我已经扩展了UIView 并使用touchMoved 委托实现了这一点,代码如下touchesMoved 委托。它工作正常。 TouchMoved 唯一缺少的是您不能直接将分隔视图滑动到顶部或底部。你必须一直拖到顶部或底部!

为了支持轻弹视图,我尝试了UIPanGestureRecognizer,但我没有看到平滑的拖动。设置父级的拆分位置会调整两个内容视图的大小,如代码所示。当我在UIGestureRecognizerStateChanged 状态下处理拆分位置更改时,只需触摸分隔线视图即可将其轻弹到顶部或底部。处理UIGestureRecognizerStateEnded 中的拆分位置更改也是如此,但我没有看到内容视图通过dividerview 滚动调整大小!

谁能告诉我如何通过调整内容视图的大小(如touchMoved)来实现分隔视图的平滑滚动和轻弹视图?任何替代方法也可以。谢谢。

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
    UITouch *touch = [touches anyObject];
    if (touch) 
        CGPoint lastPt = [touch previousLocationInView:self];
        CGPoint pt = [touch locationInView:self];
        float offset = pt.y - lastPt.y;
        self.parentViewController.splitPosition = self.parentViewController.splitPosition + offset;
    


- (void)handlePan:(UIPanGestureRecognizer*)recognizer 

    CGPoint translation = [recognizer translationInView:recognizer.view];
    CGPoint velocity = [recognizer velocityInView:recognizer.view];

    if (recognizer.state == UIGestureRecognizerStateBegan) 
     else if (recognizer.state == UIGestureRecognizerStateChanged) 
       // If I change split position here, I don't see smooth scrolling dividerview...it directly jumps to the top or bottom!
       self.parentViewController.splitPosition = self.parentViewController.splitPosition + translation.y;
     else if (recognizer.state == UIGestureRecognizerStateEnded) 
      // If I change split position here, the same thing happens at end and I don't see my divider view moving with my scrolling and resizing my views.
        self.parentViewController.splitPosition = self.parentViewController.splitPosition + translation.y;
    

初始画面

通过向底部滚动分隔视图来增加顶部视图的大小。

顶视图完全隐藏在这里,但我必须滚动分隔视图 登顶之路。我想轻弹分隔线视图,使其直接 从任何位置到顶部

【问题讨论】:

【参考方案1】:

如果我的理解正确的话,这里有两个不同的问题。

第一个:使用 GestureRecognizer 时的“不流畅”拖动。您的代码中的问题是,每次 GR 调用它的句柄方法时,您都会添加翻译。由于翻译是连续测量的,因此每次调用时都会添加更高的值(即第一次调用将 10 添加到拆分位置,第二次调用 20,第三次调用 30 等等)。

要解决这个问题,您应该在更新分割位置后将平移设置为零:

- (void)handlePan:(UIPanGestureRecognizer*)recognizer 

    CGPoint translation = [recognizer translationInView:recognizer.view];

    if (recognizer.state == UIGestureRecognizerStateChanged) 
       self.parentViewController.splitPosition = self.parentViewController.splitPosition + translation.y;
     
    [recognizer setTranslation:CGPointZero inView:recognizer.view];

第二个:为了允许用户将分割位置轻弹到顶部或底部,您可以检查 UIGestureRecognizerStateEnded 中的速度,如果超过某个值,立即将分割位置设置为顶部或底部。

但使用 UISwipeGestureRecognizer 可能更方便。

- (void)handleSwipe:(UISwipeGestureRecognizer *)gr

    if (gr.direction == UISwipeGestureRecognizerDirectionUp)
        [self.parentViewController moveSplitViewToTop];
    
    else if (gr.direction == UISwipeGestureRecognizerDirectionDown)
        [self.parentViewController moveSplitViewToBottom];
    

在这种情况下,可能有必要(不确定,也许不是)通过设置要求 SwipeGR 在 PanGR 触发之前失败:

[panGestureRecognizer requireGestureRecognizerToFail:swipeGestureRecognizer];

希望有所帮助。

编辑: 关于您的评论,我假设您的频率是指速度。如果您只使用 PanGR,您可以将上面的代码修改为 sth。像这样:

- (void)handlePan:(UIPanGestureRecognizer*)recognizer 

    CGPoint translation = [recognizer translationInView:recognizer.view];
    CGPoint velocity = [recognizer velocityInView:recognizer.view];

    if (recognizer.state == UIGestureRecognizerStateChanged) 
       self.parentViewController.splitPosition = self.parentViewController.splitPosition + translation.y;
     
    else if (recognizer.state == UIGestureRecognizerStateEnded)
        if (velocity.y > someValue)
            [self.parentViewController moveSplitViewToBottom];
        
        else if (velocity.y < someValue)
            [self.parentViewController moveSplitViewToTop];
        
    
    [recognizer setTranslation:CGPointZero inView:recognizer.view];

我不确定速度是否已签名,如果没有,您必须在 if 块中再次检查翻译。

【讨论】:

我尝试了滑动手势,但由于 10px 高度视图,该事件没有发生!不过,您的 Pan 手势识别器解决方案看起来很有趣。我不知道翻译概念。关于频率,我尝试过这样做,但频率是以坐标表示的,所以我不确定如何测量频率?您能否为此添加一些示例代码。谢谢。 完美。这就像一个魅力。非常感谢你。将 Translation 设置为 CGPointZero 是关键! :) 我已经完全删除了 touchMoved,它与 Pan 一起工作得非常好!

以上是关于iOS:用于平滑滚动和轻弹视图的手势识别器的主要内容,如果未能解决你的问题,请参考以下文章

添加手势识别器以允许在 Swift 中的 MapView 上水平滑动

iOS - 使用/传递手势识别器用于视图中的多个表视图或集合视图(Swift)

iOS 上的手势过滤

iOS - 在视图(Swift)中为多个Tableview或Collectionviews使用/传递手势识别器

UITableViewCell 上的 UIPanGestureRecognizer 覆盖 UITableView 的滚动视图手势识别器

获取点击手势识别器的标签或索引