概述
iOS可以对swipe(滑动), pinch(捏), pan(拖拽), tap(点), long-press(长按), and rotation(旋转)共6种手势进行检测。
手势识别必须驾到UIView的实例里面,一个view可以有多个手势识别。
基本步骤:
- 创建一个手势识别
- 添加到一个view上,用addGestureRecognizer
- 写一个方法,当手势发生的时候,运行这个方法。这个方法必须返回void,必须无参数或只接受一个UIGestureRecognizer的参数
- 当不需要手势的时候,移除掉,用removeGestureRecognizer
手势识别可以被分为2类:
- 不连续的:当检测到手势的时候,结束检测,调用一次方法,比如,双击
- 连续的:持续检测,不断调用方法,直到手势结束。比如旋转,手势开始于用户旋转时,结束于用户抬起手指。
UIGestureRecognizer有一个属性叫state,不连续的和连续的手势有不同的state: - 不连续的:
- UIGestureRecognizerStatePossible
- UIGestureRecognizerStateRecognized:认出手势
- UIGestureRecognizerStateFailed:手势失败
- 连续的:
- UIGestureRecognizerStatePossible
- UIGestureRecognizerStateBegan
- UIGestureRecognizerStateChanged
- UIGestureRecognizerStateEnded
- UIGestureRecognizerStateFailed
- UIGestureRecognizerStateCancelled,比如在手势过程中,有一个电话打过来
10.1 检测Swipe(滑动)
用UISwipeGestureRecognizer,一次只能检测一个方向:
var swipeRecognizer: UISwipeGestureRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
swipeRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipes:")
//只会检测向左的手势
swipeRecognizer.direction = .Left
swipeRecognizer.numberOfTouchesRequired = 1
view.addGestureRecognizer(swipeRecognizer)
}
func handleSwipes(sender: UISwipeGestureRecognizer) {
if sender.direction == .Down {
println("Down")
}
if sender.direction == .Left {
println("Left")
}
if sender.direction == .Right {
println("Right")
}
if sender.direction == .Up {
println("Up")
}
}
10.2 旋转
是属于连续的手势,用UIRotationGestureRecognizer, 不需要关心被旋转物体本来的角度,因为旋转时返回的角度都是基于0的。是一个相对的角度。
var helloWorldLabel = UILabel()
var rotaionRecognizer: UIRotationGestureRecognizer!
var rotationAngleInRadians = 0.0 as CGFloat
helloWorldLabel.text = "Hello, World"
helloWorldLabel.font = UIFont.systemFontOfSize(16)
helloWorldLabel.sizeToFit()
helloWorldLabel.center = view.center
view.addSubview(helloWorldLabel)
rotaionRecognizer = UIRotationGestureRecognizer(target: self, action: "handleRotation:")
view.addGestureRecognizer(rotaionRecognizer)
func handleRotation(sender:UIRotationGestureRecognizer) {
println("\(sender.rotation) \(rotationAngleInRadians)")
helloWorldLabel.transform = CGAffineTransformMakeRotation(rotationAngleInRadians + sender.rotation)
if sender.state == .Ended {
rotationAngleInRadians += sender.rotation
}
}
如果要在模拟器上模拟,要按住option键。
10.3 检测Pan(拖动)
属于连续手势,在End状态的时候,可能取到的位置是一个nil值:
{
var panGestureLabel: UILabel!
var panGestureRecognizer: UIPanGestureRecognizer!
//pan gesture
let labelFrame = CGRect(x: 0, y: 0, width: 150, height: 100)
panGestureLabel = UILabel(frame: labelFrame)
panGestureLabel.userInteractionEnabled = true
panGestureLabel.text = "Pan Gesture"
panGestureLabel.backgroundColor = UIColor.blackColor()
panGestureLabel.textColor = UIColor.whiteColor()
panGestureLabel.textAlignment = .Center
panGestureRecognizer = UIPanGestureRecognizer(target: self, action: "handlePanGestures:")
view.addSubview(panGestureLabel)
panGestureRecognizer.minimumNumberOfTouches = 1
panGestureRecognizer.maximumNumberOfTouches = 1
panGestureLabel.addGestureRecognizer(panGestureRecognizer)
}
func handlePanGestures(sender: UIPanGestureRecognizer) {
if sender.state != .Ended && sender.state != .Failed {
let location = sender.locationInView(sender.view!.superview)
sender.view?.center = location
}
// 如果是多手指用这个
// sender.locationOfTouch(<#touchIndex: Int#>, inView: <#UIView?#>)
}
10.4 长按
用UILongPressGestureRecognizer, 有几个属性需要注意:
- numberOfTapsRequired: 在启动这个手势需要的点击数目,tap的意思是放手指在屏幕上,然后离开,缺省是0
- numberOfTouchesRequired:touch的手指数目
- allowableMovement:手指在屏幕上移动的pixel的最大数目
- minimumPressDuration:手势触发的最短按压时间
//长按
dummyButton = UIButton.buttonWithType(.System) as! UIButton
dummyButton.frame = CGRect(x: 0, y: 0, width: 72, height: 37)
dummyButton.setTitle("My Button", forState: .Normal)
longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPressGestures:")
longPressGestureRecognizer.numberOfTouchesRequired = 2
//在识别的时候,容许有一些抖动
longPressGestureRecognizer.allowableMovement = 100
//要按多久
longPressGestureRecognizer.minimumPressDuration = 1
dummyButton.frame = CGRect(x: 100, y: 100, width: 100, height: 50)
view.addGestureRecognizer(longPressGestureRecognizer)
view.addSubview(dummyButton)
func handleLongPressGestures(sender: UILongPressGestureRecognizer) {
if sender.numberOfTouches() == 2 {
let touchPoint1 = sender.locationOfTouch(0, inView: sender.view)
let touchPoint2 = sender.locationOfTouch(1, inView: sender.view)
let midPointX = (touchPoint1.x + touchPoint2.x) / 2.0
let midPointY = (touchPoint1.y + touchPoint2.y) / 2.0
let midPoint = CGPoint(x: midPointX, y: midPointY)
dummyButton.center = midPoint
}
}
10.5 检测tap 手势
用UITapGestureRecognizer,相关的属性:
- numberOfTapsRequired: 在启动这个手势需要的点击数目,tap的意思是放手指在屏幕上,然后离开,缺省是0
- numberOfTouchesRequired:touch的手指数目
10.6 检测Pinch(捏)手势
用UIPinchGestureRecognizer:
//Pinch
let labelRect = CGRect(x: 200, y: 400, width: 50, height: 50)
pinchLabel = UILabel(frame: labelRect)
pinchLabel.backgroundColor = UIColor.blackColor()
pinchLabel.userInteractionEnabled = true
pinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: "handlePinches:")
pinchLabel.addGestureRecognizer(pinchGestureRecognizer)
view.addSubview(pinchLabel)
func handlePinches(sender: UIPinchGestureRecognizer) {
if sender.state == .Ended {
currentScale = sender.scale
} else if sender.state == .Began && currentScale != 0.0 {
sender.scale = currentScale
}
if sender.scale != CGFloat.NaN && sender.scale != 0.0 {
sender.view!.transform = CGAffineTransformMakeScale(sender.scale, sender.scale)
}
}
10.7 检测屏幕边缘的拖动手势
检测用户的手从屏幕的一边移动到你的view里面。比如划出上面的notification center和下面的控制中心。
func handleScreenEdgePan(sender: UIScreenEdgePanGestureRecognizer){
if sender.state == .Ended{ displayAlertWithTitle("Detected",
message: "Edge swipe was detected")
}
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
/* Create the Pinch Gesture Recognizer */
screenEdgeRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: "handleScreenEdgePan:")
/* Detect pans from left edge to the inside of the view */
screenEdgeRecognizer.edges = .Left
}