问题
I am implementing a custom UIGestureRecognizer
subclass.
I would like to implement velocityInView:
the same way that UIPanGestureRecognizer
has done it. But I'm not sure how to go about doing it. How do I calculate the velocity in points / second?
回答1:
Firstly, if you're using Swift, you're going to need to create a Bridging Header and #import <UIKit/UIGestureRecognizerSubclass.h>
so you can override UIGestureRegoniser
's touches began/moved/cancelled/ended methods. If you're using Objective-C just put that import
statement in the .h or .m file.
Secondly, once you've created your UIGestureRecognizer
subclass you need these variables in it:
private lazy var displayLink: CADisplayLink = {
let link = CADisplayLink(target: self, selector: Selector("timerCalled"))
link.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)
return link
}()
private var previousTouchLocation: CGPoint?
private var currentTouchLocation : CGPoint?
private var previousTime: Double?
private var currentTime : Double?
The display link is for updating the currentTime
and previousTime
.
Thirdly, to continue setting everything up you need to override the following methods, I think it's all fairly self-explanatory:
override func touchesBegan(touches: Set<NSObject>!, withEvent event: UIEvent!) {
self.state = .Began
displayLink.paused = false
}
override func touchesMoved(touches: Set<NSObject>!, withEvent event: UIEvent!) {
if let view = self.view,
touch = touches.first as? UITouch {
self.state = .Changed
let newLocation = touch.locationInView(view)
self.previousTouchLocation = self.currentTouchLocation
self.currentTouchLocation = newLocation
}
}
override func touchesEnded(touches: Set<NSObject>!, withEvent event: UIEvent!) {
self.state = .Ended
displayLink.paused = true
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
self.state = .Cancelled
displayLink.paused = true
}
Fourthly, now we can get to the more interesting bit - calculating the velocity:
func velocityInView(targetView: UIView) -> CGPoint {
var velocity = CGPoint.zeroPoint
if let view = self.view,
prevTouchLocation = self.previousTouchLocation,
currTouchLocation = self.currentTouchLocation,
previousTime = self.previousTime,
currentTime = self.currentTime {
let targetPrevLocation = view.convertPoint(prevTouchLocation, toView: targetView)
let targetCurrLocation = view.convertPoint(currTouchLocation, toView: targetView)
let deltaTime = CGFloat(currentTime - previousTime)
let velocityX = (targetCurrLocation.x - targetPrevLocation.x) / deltaTime
let velocityY = (targetCurrLocation.y - targetPrevLocation.y) / deltaTime
velocity = CGPoint(x: velocityX, y: velocityY)
}
return velocity
}
The velocity is calculated using the equation:
velocity = deltaDistance / deltaTime
In this case, take each component of the velocity (x and y) and use that equation to calculate the velocity in each axis. If you wanted to combine both components of the velocity you would use Pythagoras' Theorem like so:
let distance = hypot(targetCurrLocation.x - targetPrevLocation.x,
targetCurrLocation.y - targetPrevLocation.y)
let velocity = distance / deltaTime
Fifthly, in your view controller you can now add your gesture recognizer and use action
to get the velocity when dragging over the screen:
override func viewDidLoad() {
super.viewDidLoad()
let recognizer = VelocityGestureRecognizer(target: self, action: Selector("movedGesture:"))
self.view.addGestureRecognizer(recognizer)
}
func movedGesture(recognizer: VelocityGestureRecognizer) {
let v = recognizer.velocityInView(self.view)
println("velocity = \(v)")
}
来源:https://stackoverflow.com/questions/28552408/how-do-i-implement-velocityinview-for-a-custom-gesture-recognizer