在 iOS 中检测 PAN 手势的方向
Posted
技术标签:
【中文标题】在 iOS 中检测 PAN 手势的方向【英文标题】:Detecting the direction of PAN gesture in iOS 【发布时间】:2012-08-02 12:19:48 【问题描述】:在我的应用中有一个图像视图。我正在向该图像视图添加 PAN 手势。
这工作正常。
图像视图处于横向模式。
我想在用户向右平移时增加标签计数,并在用户向左平移时减少该计数。
我搜索了很多,但没有找到解决方案。
谁能帮助我如何检测用户平移的方向(左/右)?
【问题讨论】:
“我正在向该图像视图添加 PAN 手势。”你的意思是手势识别器? 我在谷歌上搜索了一下,第一次点击很好地解释了一切google.com/… 见***.com/a/27130070/1418457 【参考方案1】:在手势识别器的目标选择器中,使用- (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 分钟前。 Google 的第一个热门产品是 Apple 官方文档。
【讨论】:
0.0 的速度根本不是任何方向,因此更适合明确(如果 vel.x > 0.0 否则如果 vel.x 【参考方案2】:类似这样的:
- (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");
【讨论】:
【参考方案3】:我之前在 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
【讨论】:
我相信您颠倒了 .Up 和 .Down,但除此之外,谢谢!你是救生员! @AdamWaite: 将答案更新为@available(swift, deprecated: 4.2, rename: "abs") public func fabs这是一个清理后的 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
【讨论】:
也许更好地进行一些更改以不需要返回选项,例如在where
中使用>=
。我想不出一个平移手势返回“无方向”的情况。【参考方案5】:
在 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
【讨论】:
这个版本有一个严重的错误。如果 y == 0,它将返回 .down。如果 x==0,它将返回 .left。在这些情况下,您应该返回一个 nil PanDirection,就像 Adam Waite 的版本一样。 我认为您不需要在direction
中返回选项【参考方案6】:
请注意,上面亚当的 Swift 版本有一个错误。如果 y 0 应该返回 .down (它们是相反的)。
所以:
//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
【讨论】:
这里是 Swift 中的菜鸟,假设我想在向上滑动时调用一个方法,我该怎么做? @贾斯汀斯坦利 添加您的平移手势识别器,并在它的其中一个代表中进行平移,或者执行以下操作:如果识别器.direction == .up 做某事 或打开识别器.direction 并将其放在外壳中.up.【参考方案7】: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:
()
【讨论】:
以上是关于在 iOS 中检测 PAN 手势的方向的主要内容,如果未能解决你的问题,请参考以下文章