UIKit框架提供了一些预定义的GestureRecognizer.包含下列手势:
- UITapGestureRecognizer敲击手势(单击和双击)
- UIPinchGestureRecognizer(缩放手势)
- UIRotationGestureRecognizer(旋转手势)
- UISwipeGestureRecognizer(擦碰手势)
- UIPanGestureRecognizer(拖动手势)
- UILongPressGestureRecognizer(长按手势)
每一个特定的手势必须关联到view对象中才会有作用,一个view对象可以关联多个不同的特定手势,但是每一个特定的手势只能与一个view相关联。当用户触摸了view,这个GestureRecognizer就会接受到消息,它可以响应特定的触摸事件。
【1】点击手势UITapGestureRecognizer
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
tapGesture.delegate = self;
tapGesture.numberOfTapsRequired = 1; // The default value is 1.
tapGesture.numberOfTouchesRequired = 1; // The default value is 1.
[self.view addGestureRecognizer:tapGesture];
- (void)handleGesture:(UIGestureRecognizer *)sender {
UIView *view = sender.view; // 这个view是手势所属的view,也就是增加手势的那个view
switch (sender.state) {
case UIGestureRecognizerStateEnded:{
// 正常情况下只响应这个消息
break;
}
case UIGestureRecognizerStateFailed:{
break;
}
case UIGestureRecognizerStatePossible:{
break;
}
default:{
break;
}
}
}
// 询问一个手势接收者是否应该开始解释执行一个触摸接收事件
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
CGPoint currentPoint = [gestureRecognizer locationInView:self.view];
if (CGRectContainsPoint(CGRectMake(0, 0, 100, 100), currentPoint) ) {
return YES;
}
return NO;
}
// 询问delegate,两个手势是否同时接收消息,返回YES同时接收。返回NO不同时接收(如果另外一个手势返回YES,则并不能保证不同时接收消息)
// the default implementation returns NO。
// 这个函数一般在一个手势接收者要阻止另外一个手势接收自己的消息的时候调用
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return NO;
}
// 询问delegate是否允许手势接收者接收一个touch对象
// 返回YES,则允许对这个touch对象审核,NO,则不允许。
// 这个方法在touchesBegan:withEvent:之前调用,为一个新的touch对象进行调用
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
return YES;
}
【2】捏合手势 UIPinchGestureRecognizer
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
pinchGesture.delegate = self;
[self.view addGestureRecognizer: pinchGesture];
- (void)handleGesture:(UIPinchGestureRecognizer *)sender {
UIView *view = sender.view; // 这个view是手势所属的view,也就是增加手势的那个view
CGFloat scale = sender.scale;
/*
scale属性: 两手指之间的距离比例,相对距离,不是绝对距离
以刚开始的两个手指对应的两个point的之间的距离为标准,此时scale=1.
若两手指之间距离减小,则scale不断变小,当两指重合,则变为0
若两手指之间距离变大,则scale不断增大,没有上限,看屏幕多大
*/
CGFloat velocity = sender.velocity;
/*
velocity属性: 两手指之间的移动速度比例,相对速度,不是绝对速度
以刚开始的两个手指对应的两个point的之间的距离为标准,此时velocity=0.
若两手指之间距离减小,则velocity为负数,从-0开始,随着手指向里捏合的速度越快,负值越大
若两手指之间距离变大,则velocity为正数,从0开始,随着手指向外捏合的速度越快,值越大
注意:在这个过程中,出现了nan值。
*/
switch (sender.state) {
case UIGestureRecognizerStateEnded:{
break;
}
case UIGestureRecognizerStateBegan:{
break;
}
case UIGestureRecognizerStateChanged:{
break;
}
case UIGestureRecognizerStateCancelled:{
break;
}
case UIGestureRecognizerStateFailed:{
break;
}
case UIGestureRecognizerStatePossible:{
break;
}
default:{
break;
}
}
}
【3】旋转手势UIRotationGestureRecognizer
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
rotationGesture.delegate = self;
[self.view addGestureRecognizer:rotationGesture];
- (void)handleGesture:(UIRotationGestureRecognizer *)sender {
UIView *view = sender.view; // 这个view是手势所属的view,也就是增加手势的那个view
CGFloat rotation = sender.rotation;
/*
rotation属性: 可以理解为两手指之间的旋转的角度比例,相对角度,不是绝对角度
以刚开始的两个手指对应的两个point的之间的那条直线为标准,此时rotation=1.
向顺时针旋转,则rotation为正数且不断变大,当旋转360度时,rotation为2π
向逆时针旋转,则rotation为负数且不断变小,当旋转360度时,rotation为-2π
*/
CGFloat velocity = sender.velocity;
/*
velocity属性: 可以理解为两手指之间的移动速度比例,相对速度,不是绝对速度
以刚开始的两个手指对应的两个point的之间的距离为标准,此时velocity=0.
若两手指向顺时针旋转,则velocity为正数,从0开始,随着手指向里捏合的速度越快,值越大,没有上限
若两手指向逆时针旋转,则velocity为负数,从-0开始,随着手指向外捏合的速度越快,值越小,没有下限
*/
switch (sender.state) {
case UIGestureRecognizerStateEnded:{
break;
}
case UIGestureRecognizerStateBegan:{
break;
}
case UIGestureRecognizerStateChanged:{
break;
}
case UIGestureRecognizerStateCancelled:{
break;
}
case UIGestureRecognizerStateFailed:{
break;
}
case UIGestureRecognizerStatePossible:{
break;
}
default:{
break;
}
}
}
【4】滑动手势UISwipeGestureRecognizer
UISwipeGestureRecognizer *swipeGestureDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
swipeGestureDown.delegate = self;
swipeGestureDown.numberOfTouchesRequired = 1;//手指个数The default value is 1.
swipeGestureDown.direction = UISwipeGestureRecognizerDirectionDown;//同一个手势只能指定一个方向,不能同时指定多个方向,要指定多个方向 必须用多个手势
[self.view addGestureRecognizer:swipeGestureDown];
- (void)handleGesture:(UISwipeGestureRecognizer *)sender {
UIView *view = sender.view; // 这个view是手势所属的view,也就是增加手势的那个view
UISwipeGestureRecognizerDirection direction = sender.direction; //direction属性: 用来指明手势滑动的方向的。
switch (direction) {
case UISwipeGestureRecognizerDirectionRight:{
break;
}
case UISwipeGestureRecognizerDirectionLeft:{
break;
}
case UISwipeGestureRecognizerDirectionUp:{
break;
}
case UISwipeGestureRecognizerDirectionDown:{
break;
}
default:
break;
}
switch (sender.state) {
case UIGestureRecognizerStateEnded:{
break;
}
default:{
break;
}
}
}
【5】拖拽手势UIPanGestureRecognizer
UIPanGestureRecognizer *panPressGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
panPressGesture.delegate = self;
panPressGesture.maximumNumberOfTouches = NSUIntegerMax;// The default value is NSUIntegerMax.
panPressGesture.minimumNumberOfTouches = 1;// The default value is 1.
[view addGestureRecognizer:panPressGesture];
- (void)handleGesture:(UIPanGestureRecognizer *)sender {
UIView *view = sender.view; // 这个view是手势所属的view,也就是增加手势的那个view
switch (sender.state) {
case UIGestureRecognizerStateBegan:{
break;
}
case UIGestureRecognizerStateChanged:{
/*
让view跟着手指移动
1.获取每次系统捕获到的手指移动的偏移量translation
2.根据偏移量translation算出当前view应该出现的位置
3.设置view的新frame
4.将translation重置为0(十分重要。否则translation每次都会叠加,很快你的view就会移除屏幕!)
*/
CGPoint translation = [sender translationInView:self.view];
view.center = CGPointMake(sender.view.center.x + translation.x, sender.view.center.y + translation.y);
[sender setTranslation:CGPointMake(0, 0) inView:self.view];// 注意一旦你完成上述的移动,将translation重置为0十分重要。否则translation每次都会叠加,很快你的view就会移除屏幕!
break;
}
case UIGestureRecognizerStateCancelled:{
break;
}
case UIGestureRecognizerStateFailed:{
break;
}
case UIGestureRecognizerStatePossible:{
break;
}
case UIGestureRecognizerStateEnded:{
/*
当手势结束后,view的减速缓冲效果
模拟减速写的一个很简单的方法。它遵循如下策略:
计算速度向量的长度(i.e. magnitude)
如果长度小于200,则减少基本速度,否则增加它。
基于速度和滑动因子计算终点
确定终点在视图边界内
让视图使用动画到达最终的静止点
使用“Ease out“动画参数,使运动速度随着时间降低
*/
CGPoint velocity = [sender velocityInView:self.view];// 分别得出x,y轴方向的速度向量长度(velocity代表按照当前速度,每秒可移动的像素个数,分xy轴两个方向)
CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));// 根据直角三角形的算法算出综合速度向量长度
// 如果长度小于200,则减少基本速度,否则增加它。
CGFloat slideMult = magnitude / 200;
NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);
float slideFactor = 0.1 * slideMult; // Increase for more of a slide
// 基于速度和滑动因子计算终点
CGPoint finalPoint = CGPointMake(view.center.x + (velocity.x * slideFactor),
view.center.y + (velocity.y * slideFactor));
// 确定终点在视图边界内
finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
[UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
view.center = finalPoint;
} completion:nil];
break;
}
default:{
break;
}
}
}