window:触碰产生时所处的窗口,由于窗口可能发生变化,当前所在的窗口不一定是最开始的窗口。
view:触碰产生时所处的视图。由于视图可能发生变化,当前视图也不一定是最初的视图。
tapCount:短时间内轻击(tap)屏幕的次数,可根据tapCount判断单击、双击或更多的轻击。
timestamp:时间戳记录了触碰事件产生或变化时的时间。单位是秒。
phase:触碰事件在屏幕上有一个周期,即触碰开始、触碰点移动、触碰结束,中途取消。通过phase可以查看当前触碰事件在一个周期中所处的状态
根据不同的触碰状态,程序会调用相应的处理函数,这些函数包括:
//开始
-(void) touchesBegan:(NSSet *)touches withEvents:(UIEvent *)event;
//移动
-(void) touchesMoved:(NSSet *)touches withEvents:(UIEvent *)event;
//结束
-(void) touchesEnded:(NSSet *)touches withEvents:(UIEvent *)event;
//接到电话时触发
-(void) touchesCancelled:(NSSet *)touches withEvents:(UIEvent *)event;
NSSet类:类似于NSArray,用于存储对象,NSSet、NSMutableSet类声明编程接口对象,无序的集合,在内存中存储方式是不连续的
远程事件响应必须执行的两个方法:
//重写下面的方法(默认返回值为NO),返回 YES
- (BOOL)canBecomeFirstResponder
//让它成为第一响应者
- (BOOL)becomeFirstResponder
UIButton 继承自 UIControl, UIControl 继承自 UIView
ImageView 和 lablel 的默认状态是不允许用户进行交互
用xcode打开API的快捷键:command + shift + 0
UIGestureRecognizer
(是个抽象的基类,不能用它直接实例化对象,主要使用它的子类)
//初始化方法
- (instancetype _Nonnull)initWithTarget:(id _Nullable)target action:(SEL _Nullable)action
//添加监听事件
- (void)addTarget:(id _Nonnull)target action:(SEL _Nonnull)action
//移除监听事件
- (void)removeTarget:(id _Nullable)target action:(SEL _Nullable)action
//在视图中的位置
- (CGPoint)locationInView:(UIView * _Nullable)view
//对应手指在视图中的位置
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView * _Nullable)view
//手指个数
- (NSUInteger)numberOfTouches
//状态
@property(nonatomic, readonly) UIGestureRecognizerState state
//状态的枚举
typedef enum {
UIGestureRecognizerStatePossible,
UIGestureRecognizerStateBegan,
UIGestureRecognizerStateChanged,
UIGestureRecognizerStateEnded,
UIGestureRecognizerStateCancelled,
UIGestureRecognizerStateFailed,
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
} UIGestureRecognizerState;
//视图
@property(nonatomic, readonly, nullable) UIView *view
//是否允许添加手势(默认是YES)
@property(nonatomic, getter=isEnabled) BOOL enabled
下面三个方法表示我们使用手势识别器封装了,还要不要使用触摸或者延时触摸
//取消手势
@property(nonatomic) BOOL cancelsTouchesInView
//延迟开始
@property(nonatomic) BOOL delaysTouchesBegan
//延迟结束
@property(nonatomic) BOOL delaysTouchesEnded
//如果otherGestureRecognizer手势失败则调用另一个手势(调用这个方法的手势)
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer * _Nonnull)otherGestureRecognizer
//代理(代理方法见下)
@property(nonatomic, weak, nullable) id< UIGestureRecognizerDelegate > delegate
UITapGestureRecognizer 点击
//点击次数
@property(nonatomic) NSUInteger numberOfTapsRequired
//触发事件的手指数量
@property(nonatomic) NSUInteger numberOfTouchesRequired
UISwipeGestureRecognizer 滑动(轻扫,快速移动,用来监测滑动方向的)
@property(nonatomic) NSUInteger numberOfTouchesRequired
//允许滑动的方向
@property(nonatomic) UISwipeGestureRecognizerDirection direction
//方向枚举
typedef enum {
UISwipeGestureRecognizerDirectionRight = 1 << 0,
UISwipeGestureRecognizerDirectionLeft = 1 << 1,
UISwipeGestureRecognizerDirectionUp = 1 << 2,
UISwipeGestureRecognizerDirectionDown = 1 << 3
} UISwipeGestureRecognizerDirection;
UIRotationGestureRecognizer 旋转
//旋转弧度,默认是绝对值(叠加值),需要的是增量值时,需要每次rotation置0
@property(nonatomic) CGFloat rotation
//速度(每秒多少弧度,radius为1)
@property(nonatomic, readonly) CGFloat velocity
UIPinchGestureRecognizer 捏合
//scale(比例)如果需要获得增量值
@property(nonatomic) CGFloat scale
//每秒多少比例
@property(nonatomic, readonly) CGFloat velocity
UILongPressGestureRecognizer 长按
//设置当前长按最小的时长
@property(nonatomic) CFTimeInterval minimumPressDuration
@property(nonatomic) NSUInteger numberOfTouchesRequired
@property(nonatomic) NSUInteger numberOfTapsRequired
//设置允许的移动范围,在范围内手指不离开屏幕算长按,超过就算平移
@property(nonatomic) CGFloat allowableMovement
UIPanGestureRecognizer 平移(慢速移动,是用于监测偏移的量的)
@property(nonatomic) NSUInteger maximumNumberOfTouches//上不封顶
@property(nonatomic) NSUInteger minimumNumberOfTouches//默认是1
//返回的是个绝对值
- (CGPoint)translationInView:(UIView *)view
//用来重置 Translation 的值
- (void)setTranslation:(CGPoint)translation inView:(UIView *)view
- (CGPoint)velocityInView:(UIView *)view//速度
UIScreenEdgePanGestureRecognizer 屏幕边缘平移(继承自平移,它拥有平移的全部属性和方法)
//方向
@property(readwrite, nonatomic, assign) UIRectEdge edges
//枚举
typedef enum : NSUInteger {
UIRectEdgeNone = 0,//(0000 0000)这种方式是为了更好的或运算
UIRectEdgeTop = 1 << 0,//(0000 0001)
UIRectEdgeLeft = 1 << 1,//(0000 0010)
UIRectEdgeBottom = 1 << 2,//(0000 0100)
UIRectEdgeRight = 1 << 3,//(0000 1000)
UIRectEdgeAll = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
} UIRectEdge;
代理方法
//是否允许手势开始(默认YES)
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer * _Nonnull)gestureRecognizer
//是否允许手势识别器检测触摸手势(默认YES)
- (BOOL)gestureRecognizer:(UIGestureRecognizer * _Nonnull)gestureRecognizer shouldReceiveTouch:(UITouch * _Nonnull)touch
//是否允许两个手势同时有效
- (BOOL)gestureRecognizer:(UIGestureRecognizer * _Nonnull)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer * _Nonnull)otherGestureRecognizer
//下面这两个方法是用来设置谁有效,谁没效
- (BOOL)gestureRecognizer:(UIGestureRecognizer * _Nonnull)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer * _Nonnull)otherGestureRecognizer
- (BOOL)gestureRecognizer:(UIGestureRecognizer * _Nonnull)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer * _Nonnull)otherGestureRecognizer
补充
与:&
或:|
非:~
异或:不同位1,相同为0
同或:相同为1,不同位0
左移位:<<
右移位:>> (正数右移,前边空出来的位全部补0,负数全部补1)
手势识别是具有互斥的原则的,比如单击和双击,如果它识别出一种手势,其后的手势将不被识别,所以对于关联手势,要做特殊处理以帮助程序甄别,应该把当前手势归结到哪一类手势里面。比如,单击和双击并存时,如果不做处理,它就只能发送出单击的消息。为了能够识别出双击手势,就需要做一个特殊处理逻辑,即先判断手势是否是双击,在双击失效的情况下作为单击手势处理。使用如下方法:
[singleRecognizer requireGestureRecognizerToFail:doubleRecognizer];
单击和双击
//单击
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(singleAction:)];
singleTap.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:singleTap];
//双击
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleAction:)];
doubleTap.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:doubleTap];
//建立单击手势识别器和双击手势识别器的依赖关系
[singleTap requireGestureRecognizerToFail:doubleTap];
长按手势
UILongPressGestureRecognizer *longPressGestion = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressAction:)];
longPressGestion.minimumPressDuration = 2;
[self.view addGestureRecognizer:longPressGestion];
-(void)longPressAction:(UILongPressGestureRecognizer *)gesture{
//需要判断一下是否是开始点击状态,否则会调用两次这个方法
if (gesture.state != UIGestureRecognizerStateBegan) {
return;
}
NSLog(@"长按了");
}
关于滑动手势的状态,只有 ended状态 才能捕获到
UIMenuItem(菜单)
//初始化菜单
- (instancetype _Nonnull)initWithTitle:(NSString * _Nonnull)title action:(SEL _Nonnull)action
@property(nonatomic, copy, nonnull) NSString *title
@property(nonatomic, nonnull) SEL action
UIMenuController(菜单控制器,全局单例对象)
//创建对象
+ (UIMenuController * _Nonnull)sharedMenuController
//存放菜单的数组
@property(nonatomic, copy, nullable) NSArray *menuItems
//设置在哪个位置显示菜单
- (void)setTargetRect:(CGRect)targetRect inView:(UIView * _Nonnull)targetView
//显示菜单
- (void)setMenuVisible:(BOOL)menuVisible animated:(BOOL)animated
菜单代码举例
- (IBAction)showResetenu:(UILongPressGestureRecognizer *)sender {
if (sender.state != UIGestureRecognizerStateBegan) {
return;
}
//创建UIMenuItem对象
UIMenuItem *resetitem = [[UIMenuItem alloc]initWithTitle:@"Reset" action:@selector(resetView)];
//创建UIMenuController对象
UIMenuController * menuController = [UIMenuController sharedMenuController];
//都有哪些Item,放到数组中
menuController.menuItems = @[resetitem];
//item放到哪个位置
CGPoint location = [sender locationInView:self.view];
[menuController setTargetRect:CGRectMake(location.x, location.y, 0, 0) inView:self.view];
//设置成为第一响应者(必须有第一响应,才能显示出菜单)
[self becomeFirstResponder];
//显示item
[menuController setMenuVisible:YES animated:YES];
//标记将要复位的视图
_view2Reset = sender.view;
}
//允许成为第一响应
-(BOOL)canBecomeFirstResponder{
return YES;
}
//复位方法
-(void)resetView{
[UIView animateWithDuration:.3 animations:^{
_view2Reset.transform = CGAffineTransformIdentity;
}];
}