在iOS中检测PAN手势的方向

时间:2012-08-02 12:19:49

标签: objective-c ios cocoa-touch

在我的应用程序中有一个图像视图。我将PAN手势添加到该图像视图。

这很好。

图像视图处于横向模式。

我希望在用户向右平移时增加标签数量,并在用户向左平移时减少该数量。

我google了很多,但没有找到解决方案。

任何人都可以帮助我如何检测用户平移的方向(左/右)?

7 个答案:

答案 0 :(得分:88)

在手势识别器的目标选择器中,使用- (CGPoint)velocityInView:(UIView *)view;

- (void)panRecognized:(UIPanGestureRecognizer *)rec
{
    CGPoint vel = [rec velocityInView:self.view];
    if (vel.x > 0)
    {
        // user dragged towards the right
        counter++;
    }
    else
    {
        // user dragged towards the left
        counter--;
    }
}

P.s。:直到约。我才知道这种方法。 3分钟前谷歌首次点击之一是官方的Apple文档。

答案 1 :(得分:36)

这样的事情:

- (void)pan:(UIPanGestureRecognizer *)sender
{

    typedef NS_ENUM(NSUInteger, UIPanGestureRecognizerDirection) {
        UIPanGestureRecognizerDirectionUndefined,
        UIPanGestureRecognizerDirectionUp,
        UIPanGestureRecognizerDirectionDown,
        UIPanGestureRecognizerDirectionLeft,
        UIPanGestureRecognizerDirectionRight
    };

    static UIPanGestureRecognizerDirection direction = UIPanGestureRecognizerDirectionUndefined;

    switch (sender.state) {

        case UIGestureRecognizerStateBegan: {

            if (direction == UIPanGestureRecognizerDirectionUndefined) {

                CGPoint velocity = [sender velocityInView:recognizer.view];

                BOOL isVerticalGesture = fabs(velocity.y) > fabs(velocity.x);

                if (isVerticalGesture) {
                    if (velocity.y > 0) {
                        direction = UIPanGestureRecognizerDirectionDown;
                    } else {
                        direction = UIPanGestureRecognizerDirectionUp;
                    }
                }

                else {
                    if (velocity.x > 0) {
                        direction = UIPanGestureRecognizerDirectionRight;
                    } else {
                        direction = UIPanGestureRecognizerDirectionLeft;
                    }
                }
            }

            break;
        }

        case UIGestureRecognizerStateChanged: {
            switch (direction) {
                case UIPanGestureRecognizerDirectionUp: {
                    [self handleUpwardsGesture:sender];
                    break;
                }
                case UIPanGestureRecognizerDirectionDown: {
                    [self handleDownwardsGesture:sender];
                    break;
                }
                case UIPanGestureRecognizerDirectionLeft: {
                    [self handleLeftGesture:sender];
                    break;
                }
                case UIPanGestureRecognizerDirectionRight: {
                    [self handleRightGesture:sender];
                    break;
                }
                default: {
                    break;
                }
            }
        }

        case UIGestureRecognizerStateEnded: {
            direction = UIPanGestureRecognizerDirectionUndefined;   
            break;
        }

        default:
            break;
    }

}

- (void)handleUpwardsGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Up");
}

- (void)handleDownwardsGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Down");
}

- (void)handleLeftGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Left");
}

- (void)handleRightGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Right");
}

答案 2 :(得分:15)

我之前在Swift中的回答

public enum Direction: Int {
    case Up
    case Down
    case Left
    case Right

    public var isX: Bool { return self == .Left || self == .Right }
    public var isY: Bool { return !isX }
}

public extension UIPanGestureRecognizer {

    public var direction: Direction? {
        let velocity = velocityInView(view)
        let vertical = fabs(velocity.y) > fabs(velocity.x)
        switch (vertical, velocity.x, velocity.y) {
        case (true, _, let y) where y < 0: return .Up
        case (true, _, let y) where y > 0: return .Down
        case (false, let x, _) where x > 0: return .Right
        case (false, let x, _) where x < 0: return .Left
        default: return nil
        }
    }
}

答案 3 :(得分:9)

这是一个清理过的Swift 3版本,其中包含使用示例:

public enum PanDirection: Int {
    case up, down, left, right
    public var isVertical: Bool { return [.up, .down].contains(self) }
    public var isHorizontal: Bool { return !isVertical }
}

public extension UIPanGestureRecognizer {

    public var direction: PanDirection? {
        let velocity = self.velocity(in: view)
        let isVertical = fabs(velocity.y) > fabs(velocity.x)
        switch (isVertical, velocity.x, velocity.y) {
        case (true, _, let y) where y < 0: return .up
        case (true, _, let y) where y > 0: return .down
        case (false, let x, _) where x > 0: return .right
        case (false, let x, _) where x < 0: return .left
        default: return nil
    }

}

@IBAction func pan(recognizer: UIPanGestureRecognizer) {        
    if let direction = recognizer.direction {
        if direction.isVertical {
            //do what you want when pan is vertical
        } else if direction == .left {
            //do what you want when pan is left
        }
    }
}

答案 4 :(得分:1)

请注意,上面的Adam的Swift版本有错误。如果y&lt; .up应该返回。如果y> 0,则返回0和.down 0(他们反转)。

所以:

//MARK: - Direction
internal enum Direction {
    case up
    case down
    case left
    case right
}

//MARK: - UIPanGestureRecognizer
internal extension UIPanGestureRecognizer {
    internal var direction: Direction? {
        let velocity = velocityInView(view)
        let isVertical = fabs(velocity.y) > fabs(velocity.x)

        switch (isVertical, velocity.x, velocity.y) {
            case (true, _, let y) where y < 0: return .up
            case (true, _, let y) where y > 0: return .down
            case (false, let x, _) where x > 0: return .right
            case (false, let x, _) where x < 0: return .left
            default: return nil
        }
    }
}

答案 5 :(得分:1)

在Swift 3上重写Adam Waite版本

List<String> newItemList = new List<string>();
private void AddButton_Click(object sender, EventArgs e)
{
    string newItem = NameTextBox.Text + "\t" +  QuantityBox.Value.ToString()    + "\t" + PriceBox.Text;

    newItemList.Add(newItem);
    for(int i = 0; i < newItemList.Count; i++)
    {
        BasketBox.Text = newItemList[i] + "\n";
    }
}

答案 6 :(得分:0)

velocity判断对我来说太敏感了,用户很容易将拍打屏幕与平移一小部分混合在一起。

所以我使用自定义UIPanGestureRecognizer雨燕5

enum Orientation{
    case lhs, rhs, `default`
}



class HPan: UIPanGestureRecognizer {

    var first: CGPoint?
    var orient = .default

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)

        state = .began
        first = touches.first?.location(in: view?.window)
    }


    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        if state == .cancelled{
            return
        }
        if let location = touches.first?.location(in: view?.window), let begin = first{
          let magicDistance: CGFloat = 20
          if location.x - begin.x > magicDistance{
               orient = .rhs
               state = .ended
          }  
          else if begin.x - location.x > magicDistance{
               orient = .lhs
               state = .ended
          }  
        }

    }



    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesEnded(touches, with: event)
        state = .ended
    }



    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesCancelled(touches, with: event)
        state = .cancelled
    }


    override func reset() {
        super.reset()

        state = .possible
        isRight = false
        orient = .default
    }
}

像这样打电话:

@objc func push(_ gesture: RightPan){
        if gesture.state == UIGestureRecognizer.State.ended{
            switch gesture.orient{
                case .lhs:
                     counter -= 1
                case .rhs:
                     counter += 1
                default:
                    ()        
            }
        }

    }