iOS手势处理
iOS手势有着如下几种:
- UITapGestureRecognizer
- UIPinchGestureRecognizer
- UIRotationGestureRecognizer
- UISwipeGestureRecognizer
- UIPanGestureRecognizer
- UILongPressGestureRecognizer
上面的手势对应的操作是:
- Tap
(点一下) - Pinch
(二指往內或往外拨动,平时经常用到的缩放) 矩阵变换 - Rotation
(旋转)
矩阵变换 - Swipe
(滑动,快速移动) - Pan
(拖移,慢速移动)
矩阵变换 - LongPress
(长按)
注意:以下示例均把手势封装进一个View当中
UITapGestureRecognizer -
点击手势
GestureView.h + GestureView.m
#import <UIKit/UIKit.h>@interface GestureView : UIView
@end
GestureView.h
#import "GestureView.h"@interface GestureView ()
@property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
@property (nonatomic, strong) CALayer *colorLayer;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// 初始化手势,给手势指定响应事件的对象
_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureEvent:)];
_colorLayer = [CALayer layer];
_colorLayer.frame = self.bounds;[self.layer addSublayer:_colorLayer];
// 将手势与区域绑定
[self addGestureRecognizer:_tapGesture];
}
return self;
}- (void)gestureEvent:(UIGestureRecognizer *)sender {
_colorLayer.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 255.f
green:arc4random() % 255 / 255.f
blue:arc4random() % 255 / 255.f
alpha:1.0f].CGColor;
}@end
GestureView.m
- (void)addGestureRecognizer:(UIGestureRecognizer
*)gestureRecognizer
Attaching a gesture recognizer to a view defines the scope of the
represented gesture, causing it to receive touches hit-tested to that view
and all of its subviews. The view establishes a strong reference to the
gesture recognizer.
将手势识别器附着在一个view上,实际上定义了一个手势接收的区域,会将接收到的触摸事件传递给这个view以及这个view的说有的subviews.这个view会对这个手势识别器强引用.
可以总结两点:
1.
手势会传递给这个view中所有的subviews
2. view会强引用手势识别器
使用如下:
点击手势有两个参数可以设置:
numberOfTapsRequired
点击几次触发事件(默认是1)
numberOfTouchesRequired 需要几个手指点击(默认是1)
UIPinchGestureRecognizer
-
缩放
GestureView.h + GestureView.m
#import <UIKit/UIKit.h>@interface GestureView : UIView
@end
GestureView.h
#import "GestureView.h"@interface GestureView ()
@property (nonatomic, strong) UIPinchGestureRecognizer *pinchGesture;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// 初始化手势,给手势指定响应事件的对象
_pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureEvent:)];// 将手势与区域绑定
[self addGestureRecognizer:_pinchGesture];
}
return self;
}- (void)gestureEvent:(UIPinchGestureRecognizer *)sender
{
//
self.transform = CGAffineTransformScale(self.transform, sender.scale, sender.scale);
sender.scale = 1;
}@end
GestureView.m
缩放手势会用到矩阵变换.
UIRotationGestureRecognizer
- 旋转
GestureView.h + GestureView.m
#import <UIKit/UIKit.h>@interface GestureView : UIView
@end
GestureView.h
#import "GestureView.h"@interface GestureView ()
@property (nonatomic, strong) UIRotationGestureRecognizer *rotationGesture;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// 初始化手势,给手势指定响应事件的对象
_rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureEvent:)];// 将手势与区域绑定
[self addGestureRecognizer:_rotationGesture];
}
return self;
}- (void)gestureEvent:(UIRotationGestureRecognizer *)sender
{
// 此处用到了矩阵变换
self.transform = CGAffineTransformRotate(self.transform, sender.rotation);
sender.rotation = 0;
}
GestureView.m
UISwipeGestureRecognizer
- 滑动
GestureView.h + GestureView.m
#import <UIKit/UIKit.h>@interface GestureView : UIView
@end
GestureView.h
#import "GestureView.h"@interface GestureView ()
@property (nonatomic, strong) UISwipeGestureRecognizer *swipeGesture;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// 初始化手势,给手势指定响应事件的对象
_swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureEvent:)];
_swipeGesture.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight;// 将手势与区域绑定
[self addGestureRecognizer:_swipeGesture];
}
return self;
}- (void)gestureEvent:(UISwipeGestureRecognizer *)sender
{
NSLog(@"left or right");
}@end
GestureView.m
UIPanGestureRecognizer -
平移
GestureView.h + GestureView.m
#import <UIKit/UIKit.h>@interface GestureView : UIView
@end
GestureView.h
#import "GestureView.h"@interface GestureView ()
@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// 初始化手势,给手势指定响应事件的对象
_panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureEvent:)];// 将手势与区域绑定
[self addGestureRecognizer:_panGesture];
}
return self;
}- (void)gestureEvent:(UIPanGestureRecognizer *)sender
{
// 此处用到了矩阵变换
CGPoint translation = [sender translationInView:self];self.center = CGPointMake(self.center.x + translation.x,
self.center.y + translation.y);[sender setTranslation:CGPointZero
inView:self];
}@end
GestureView.m
UILongPressGestureRecognizer
- 长按手势
GestureView.h + GestureView.m
#import <UIKit/UIKit.h>@interface GestureView : UIView
@end
GestureView.h
#import "GestureView.h"@interface GestureView ()
@property (nonatomic, strong) UILongPressGestureRecognizer *longPressGesture;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// 初始化手势,给手势指定响应事件的对象
_longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureEvent:)];
_longPressGesture.minimumPressDuration = 2.0f;// 将手势与区域绑定
[self addGestureRecognizer:_longPressGesture];
}
return self;
}- (void)gestureEvent:(UILongPressGestureRecognizer *)sender
{
NSLog(@"触发事件");
}@end
GestureView.m
问题:如何处理一个view中添加了两个手势,1个是单击的手势,一个是双击的手势呢?
可以使用这个方法requireGestureRecognizerToFail:
#import "GestureView.h"@interface GestureView ()
@property (nonatomic, strong) UITapGestureRecognizer *tapGesture1;
@property (nonatomic, strong) UITapGestureRecognizer *tapGesture2;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// 单击手势
_tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(gesture1Event:)];
_tapGesture1.numberOfTapsRequired = 1;// 双击手势
_tapGesture2 = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(gesture2Event:)];
_tapGesture2.numberOfTapsRequired = 2;// 注意: 判断双击手势需要时间,也就是说会有延时
// 有事件触发时,先判断是不是 双击手势,如果不是就执行 单击手势
[_tapGesture1 requireGestureRecognizerToFail:_tapGesture2];// 将手势与区域绑定
[self addGestureRecognizer:_tapGesture1];
[self addGestureRecognizer:_tapGesture2];
}
return self;
}- (void)gesture1Event:(UIGestureRecognizer *)sender {
NSLog(@"1");
}- (void)gesture2Event:(UIGestureRecognizer *)sender {
NSLog(@"2");
}@end
GestureView.m
实际上,这种方式会有延时感-_-!!!!
问题:如何将长按手势和拖拽手势合并在一起呢?
我们需要用代理实现,实现以下的方法:
-
(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer
Asks the delegate if two gesture
recognizers should be allowed to recognize gestures
simultaneously.
询问这个代理,是否允许两个手势同时触发.
#import "GestureView.h"@interface GestureView ()<UIGestureRecognizerDelegate>
{
BOOL shouldAllowPan;
}@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
@property (nonatomic, strong) UILongPressGestureRecognizer *longPressGesture;
@end@implementation GestureView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// 初始化时不允许拖拽
shouldAllowPan = NO;_panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(panEvent:)];
[self addGestureRecognizer:_panGesture];
_panGesture.delegate = self;_longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
action:@selector(longPressEvent:)];
_longPressGesture.minimumPressDuration = 1.0f;
[self addGestureRecognizer:_longPressGesture];
_longPressGesture.delegate = self;
}
return self;
}- (void)panEvent:(UIPanGestureRecognizer *)sender {
if(shouldAllowPan == YES)
{
// 移动的操作
CGPoint translation = [sender translationInView:self];
self.center = CGPointMake(self.center.x + translation.x,
self.center.y + translation.y);[sender setTranslation:CGPointZero
inView:self];
}
else if(sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateCancelled)
{
shouldAllowPan = NO;
}
}- (void)longPressEvent:(UIGestureRecognizer *)sender
{
// 长按开始
if(UIGestureRecognizerStateBegan == sender.state)
{
NSLog(@"长按开始");
self.backgroundColor = [UIColor redColor];
shouldAllowPan = NO;
}// 长按进行中
if(UIGestureRecognizerStateChanged == sender.state)
{
NSLog(@"长按进行中");
shouldAllowPan = YES;
}// 长按结束
if(UIGestureRecognizerStateEnded == sender.state)
{
NSLog(@"长按结束");
self.backgroundColor = [UIColor blackColor];
shouldAllowPan = NO;
}
}// 是否允许多个手势同时触发
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
// 允许
return YES;
}// 是否允许继续跟踪触摸事件
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// 条件满足的手势会被传递进来(如果是移动手势,)
if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && shouldAllowPan == NO)
{
return NO;
}return YES;
}@end
GestureView.m
根据手势状态来识别手势触发事件的全称细节是十分重要的.
iOS手势处理