ios 在iOS中检测PAN手势的方向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11777281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:33:48  来源:igfitidea点击:

Detecting the direction of PAN gesture in iOS

objective-cioscocoa-touch

提问by suji

In my app there is a image view.Im adding PAN gesture to that image view.

在我的应用程序有一个图像view.Im加入PAN的姿态到图像视图。

This is working fine.

这工作正常。

The image view is in landscape mode.

图像视图处于横向模式。

I want to increase a count in label while user pan to right direction and decrease that count while user pan to left direction.

我想在用户向右平移时增加标签中的计数,并在用户向左平移时减少该计数。

I googled a lot but didn't find a solution for this.

我用谷歌搜索了很多,但没有找到解决方案。

Can anyone please help me how to detect the direction in which the user is panning(left/right)?

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

回答by

In the target selector of your gesture recognizer, use - (CGPoint)velocityInView:(UIView *)view;:

在手势识别器的目标选择器中,使用- (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.: I didn't know about this method until approx. 3 minutes before. One of Google's first hits was the official Apple documentation.

Ps:直到大约我才知道这种方法。3 分钟前。谷歌的第一批热门产品之一是苹果的官方文档。

回答by Adam Waite

Something like this:

像这样的东西:

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

回答by Adam Waite

My previous answer in Swift

我之前在 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
        }
    }
}

回答by Harris

Here is a cleaned up Swift 5 version, with example of usage:

这是一个清理过的 Swift 5 版本,以及使用示例:

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 {

   var direction: PanDirection? {
        let velocity = self.velocity(in: view)
        let isVertical = abs(velocity.y) > abs(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
        }
    }
}

回答by Bohdan Savych

Rewrite Adam Waite version on Swift 3

在 Swift 3 上重写 Adam Waite 版本

public enum PanDirection: Int {
    case up,
    down,
    left,
    right

    public var isX: Bool {
        return self == .left || self == .right
    }

    public var isY: Bool {
        return !isX
    }
}

extension UIPanGestureRecognizer {
    var direction: PanDirection? {
        let velocity = self.velocity(in: view)
        let vertical = fabs(velocity.y) > fabs(velocity.x)
        switch (vertical, velocity.x, velocity.y) {
        case (true, _, let y):
            return y < 0 ? .up : .down

        case (false, let x, _):
            return x > 0 ? .right : .left
        }
    }
}

回答by Justin Stanley

Note that Adam's Swift version above has a mistake. .up should return if y < 0 and .down should return if y > 0 (they're reversed).

注意上面 Adam 的 Swift 版本有一个错误。如果 y < 0 则 .up 应该返回,如果 y > 0 则 .down 应该返回(它们是相反的)。

So:

所以:

//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
        }
    }
}

回答by dengST30

judging by velocityis too sensitive to me, user easily mixed tapping screen with panning a small part.

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

So I use custom UIPanGestureRecognizer. Swift 5

所以我使用自定义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
    }
}

Call like this:

像这样调用:

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

    }