将 UIView 移动限制为仅垂直或水平轴

Posted

技术标签:

【中文标题】将 UIView 移动限制为仅垂直或水平轴【英文标题】:Limit UIView movement to only vertical or horizontal axis 【发布时间】:2015-02-13 15:34:50 【问题描述】:

我正在使用 PanGestureRecognizer 并在 UIGestureRecognizerStateChanged 中让用户手指移动屏幕上的视图。我将它用于类似 Tinder 的滑动手势,我现在想将视图的移动限制在水平轴或垂直轴上,无论用户开始滑动的方向是什么。我一直在上下搜索,但在这里没有找到合适的东西。

有没有什么聪明的方法可以根据用户开始滑动视图的方向来限制轴的移动?

非常感谢!

更新:这是移动视图的当前代码:

- (void)dragged:(UIPanGestureRecognizer *)gestureRecognizer

    CGFloat xDistance = [gestureRecognizer translationInView:self].x;
    CGFloat yDistance = [gestureRecognizer translationInView:self].y;
//    xDistance = 0;

    [parentView dragged:yDistance];

    switch (gestureRecognizer.state) 
        case UIGestureRecognizerStateBegan:
            self.originalPoint = self.center;
            break;
        ;
        case UIGestureRecognizerStateChanged:
            CGFloat rotationAngel = 0;
            CGFloat scale = 1;//MAX(scaleStrength, 0.93);
            CGAffineTransform transform = CGAffineTransformMakeRotation(rotationAngel);
            CGAffineTransform scaleTransform = CGAffineTransformScale(transform, scale, scale);
            self.transform = scaleTransform;
            self.center = CGPointMake(self.originalPoint.x + xDistance, self.originalPoint.y + yDistance);
            ...
            break;
        ;
        case UIGestureRecognizerStateEnded: 
            float moveDistAction = 60;
            if (yDistance > moveDistAction) 
                // view swiped down
                ...
             else if (yDistance < -moveDistAction) //100 150
                // view swiped up 
                ...
             else 
                // dragging cancelled
                ...
            
            break;
        ;
        case UIGestureRecognizerStatePossible:break;
        case UIGestureRecognizerStateCancelled:break;
        case UIGestureRecognizerStateFailed:break;
    

【问题讨论】:

发布您当前的代码 您是否已有允许任意移动的代码?发布该代码,以便我们查看您拥有的内容。然后我们可以帮助您将其限制在一个方向。 【参考方案1】:

gestureRecognizerShouldBegin:你可以知道那个方向:

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer 
    CGPoint translation = [gestureRecognizer translationInView:self.view];
    self.isVerticalPan = fabs(translation.y) > fabs(translation.x); // BOOL property

    return YES;

然后在UIGestureRecognizerStateChanged 上,您可以根据isVerticalPan 属性执行以下操作:

CGPoint translation = [gesture translationInView:self.view];
CGPoint displacement = (self.isVerticalPan) ? CGPointMake(0, translation.y) : CGPointMake(translation.x, 0);

self.viewToMove.transform = CGAffineTransformMakeTranslation(displacement.x, displacement.y);

【讨论】:

谢谢。我投票给你作为正确答案。尽管@DeepFriedTwinkie 的另一个答案也是正确的。我最终使用了这个并且有一个垂直或水平移动: - (void)dragged:(UIPanGestureRecognizer *)gestureRecognizer CGFloat xDistance = [gestureRecognizer translationInView:self].x; CGFloat yDistance = [gestureRecognizer translationInView:self].y; if (isVerticalPan) xDistance = 0; 其他 yDistance = 0; `【参考方案2】:

您可以通过实现gestureRecognizerShouldBegin: 委托方法来做到这一点。在以下实现中,我正在检查大约 20 度的水平滑动。但是,您可以检查水平或垂直滑动。 (我会使用一些小角度,因为用户很难沿着直线移动。)

- (BOOL) gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 
    // Ensure that the user is only panning mostly horizontally
    // This allows the view to be placed in a scrollview that scrolls vertically
    // Up/Down drags in the body of the view will be passed to the scroll view
    if (gestureRecognizer == self.panGesture) 

        CGPoint velocity = [self.panGesture velocityInView:self.panGesture.view];

        double radian = atan(velocity.y/velocity.x);
        double degree = radian * 180 / M_PI;

        double thresholdAngle = 20.0;
        if (fabs(degree) > thresholdAngle) 
            return NO;
        
    
    return YES;

免责声明:我很确定我在这里的某个地方找到了这个解决方案,但我找不到它。所以,向这个问题的原始解决者道歉......

【讨论】:

以上是关于将 UIView 移动限制为仅垂直或水平轴的主要内容,如果未能解决你的问题,请参考以下文章

WPF 窗口仅垂直拖动

添加 AVCaptureVideoPreviewLayer 子视图时 UIView 忽略大小限制

通过 plotyy 在 MATLAB 中绘制 2 个垂直轴时设置轴限制

SceneKit:如何将节点的移动限制在本地的一个轴上,而不是整个世界

SwiftUI Drag 事件如何限制仅检测水平/垂直滚动

自动布局对齐到中心(垂直或水平)与常数