【问题标题】:How to pass pan gesture to UICollectionVIew from UICollectionViewCell?如何从 UICollectionViewCell 将平移手势传递给 UICollectionVIew?
【发布时间】:2014-07-09 16:14:37
【问题描述】:

我有一个UICollectionView 实现自定义UICollectionViewCells 的基于网格的布局。为了让单元格响应拖动,我分别为每个单元格添加了UIPanGestureRecognizer

UICollectionView 在我从单元格之间的点开始向下和向左/向右滑动时仍会滚动(水平),但只要将平移手势识别器添加到单元格,CollectionView 似乎拒绝当我在单元格内开始滑动点击时滚动。

现在,我将水平左/右拖动与垂直向上/向下拖动分开,因此将单元格拖出(垂直滑动)和滚动CollectionView(水平滑动)之间不应该有任何冲突。在这种情况下,如何将滑动传递给集合/滚动视图,以便它知道像正常一样滚动?必须从单元格之间的边界或间距开始,真的很烦人。

从单元格中移除平移手势后,无论我开始在单元格上还是在单元格之间滑动,滚动都会正常工作。

编辑:下面发布为当前代码的所需平移手势行为

// Handle pans by detecting swipes:
-(void) handlePan:(UIPanGestureRecognizer*)recognizer
{
    // Calculate touch location
    CGPoint touchXY = [recognizer locationInView:masterWindowView];

    // Handle touch
    if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        gestureWasHandled = NO;
        pointCount = 1;
        startPoint = touchXY;
    }

    if (recognizer.state == UIGestureRecognizerStateChanged)
    {
        ++pointCount;

        // Calculate whether a swipe has occurred
        float dX = deltaX(touchXY, startPoint);
        float dY = deltaY(touchXY, startPoint);

        BOOL finished = YES;
        if ((dX > kSwipeDragMin) && (ABS(dY) < kDragLimitMax)) {
            touchType = TouchSwipeLeft;
            NSLog(@"LEFT swipe detected");
            [recognizer requireGestureRecognizerToFail:recognizer];
            //[masterScrollView handlePan]
        }
        else if ((dX < -kSwipeDragMin) && (ABS(dY) < kDragLimitMax)) {
            touchType = TouchSwipeRight;
            NSLog(@"RIGHT swipe detected");
            [recognizer requireGestureRecognizerToFail:recognizer];
        }
        else if ((dY > kSwipeDragMin) && (ABS(dX) < kDragLimitMax)) {
            touchType = TouchSwipeUp;
            NSLog(@"UP swipe detected");
        }
        else if ((dY < -kSwipeDragMin) && (ABS(dX) < kDragLimitMax)) {
            touchType = TouchSwipeDown;
            NSLog(@"DOWN swipe detected");
        }
        else
            finished = NO;

        // If unhandled and downward, produce a new draggable view
        if (!gestureWasHandled && finished && (touchType == TouchSwipeDown))
        {

            [self.delegate cellBeingDragged:self];
            dragView.center = touchXY;
            dragView.hidden = NO;
            dragView.backgroundColor = [UIColor clearColor];


            masterScrollView.scrollEnabled = NO; // prevent user from scrolling during
            gestureWasHandled = YES;
        }
        else if (gestureWasHandled)
        {
            // allow continued dragging after detection
            dragView.center = touchXY;
        }
    }

    if (recognizer.state == UIGestureRecognizerStateEnded)
    {
        // ensure that scroll view returns to scrollable
        if (gestureWasHandled) {
            [self.delegate cell:self dragEndedAt:touchXY];
        }
    }
}

// Allow simultaneous recognition
-(BOOL) gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
{
    return YES;
}

此代码适用于每个单独的单元格。当附加到 UICollectionView 作为其手势识别器时,它不起作用,实际上它会停止所有滚动。

【问题讨论】:

  • 代码在哪里?您的手势识别器代码应该存在于您的视图控制器中。 gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer 方法允许同时运行两个不同的手势,不是一个手势被两个不同的视图识别 - 这是你想要的吗?

标签: ios objective-c foundation


【解决方案1】:

不要将UIPanGestureRecognizer 附加到每个单元格(这会降低性能),而是将UIPanGestureRecognizer 添加到UICollectionView,当平移手势发生时使用locationInView 来获取UICollectionView 中的点,其中pan 启动,然后 indexPathForItemAtPoint 将返回您应该设置动画的单元格的索引路径。

这样,您的整个集合视图将只有一个手势识别器(好!),同时还保持视图控制器中的控制(如您所愿) - 双赢!

使用此解决方案,您将在视图控制器中实现gestureRecognizer:shouldReceiveTouch:,获取给定的gestureRecognizer,确保它是您的UIPanGestureRecognizer,并使用它的translationInView: 方法来确定平移是在X 轴还是Y 轴上.使用该信息来决定是否要返回 YES 或 NO。例如:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
  if([gestureRecognizer isEqual:myTapGesture]) {
    CGPoint point = [gestureRecognizer translationInView:self.collectionView];
    if(point.x != 0) { //adjust this condition if you want some leniency on the X axis
      //The translation was on the X axis, i.e. right/left, 
      //so this gesture recognizer shouldn't do anything about it
      return NO;
    }
  }
  return YES;
}

【讨论】:

  • 我试过这个,UICollectionView 完全停止滚动,除了没有检测到我在每个单独的单元格上的滑动。我回到了原来的方法,至少让我可以通过在图标之间触摸来滚动!
  • 显示一些关于您尝试过的内容以及如何实现我提出的解决方案的代码。我应该补充一点,您应该已经实现了UIGestureRecognizerDelegate 协议(特别是gestureRecognizer:shouldReceiveTouch:)来决定一个单元格是否应该接收手势。
  • 实际上,是的,了解我必须覆盖的委托函数以及是否在 ViewController、UICollectionView、UICollectionViewFlowLayout 或 UICollectionViewCell 上覆盖它们会很有帮助。我已经覆盖了handleGestureSimultaneously 以始终返回YES。稍后将在此处发布代码
  • 代码已发布!谢谢!
  • 所有手势识别方法都应该在视图控制器中,或者可能在自定义类中,但不在视图或流布局子类中。
【解决方案2】:

拥有 -shouldReceiveTouch: 和 -shouldRecognizeSimultaneouslyWithGestureRecognizer: 返回 YES,添加 UIGestureRecognizerDelegate 作为您的类协议列表,并将您的手势委托委托给 -viewDidLoad 中的 self。

yourGesture.delegate = self;

【讨论】:

  • @Cindeselia 的答案是否被接受?
猜你喜欢
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 2018-02-25
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2014-01-22
  • 1970-01-01
相关资源
最近更新 更多