iOS里有三种事件:触摸(touch)、加速(motion)、远程控制
在UIResponder里,有以下事件处理
// 触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
// 加速计事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
// 远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
响应者:继承UIResponder的对象称之为响应者对象,能够处理touchesBegan等触摸事件
当一个Touch事件产生时,要先找到响应者,iOS通过Hit-Test机制来寻找响应者,每一个UIView(继承自UIResponder)都有以下的方法
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
HitTest的顺序
UIApplication -> UIWindow -> Root View -> subview -> ··· -> initalView
sendEvent:
方法传递事件hitTest:withEvent:
方法寻找触碰点所在的视图hitTest:withEvent:
原理
// point是该视图的坐标系上的点
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// 1.判断自己能否接收触摸事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
// 2.判断触摸点在不在自己范围内
if (![self pointInside:point withEvent:event]) return nil;
// 3.从后往前遍历自己的子控件,看是否有子控件更适合响应此事件
int count = self.subviews.count;
for (int i = count - 1; i >= 0; i--) {
UIView *childView = self.subviews[i];
CGPoint childPoint = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childPoint withEvent:event];
if (fitView) {
return fitView;
}
}
// 没有找到比自己更合适的view
return self;
}
当找到最合适的响应者之后, 便会调用控件相应的touches方法来作具体处理. 并将该事件随着响应者链条往回传递, 交给上一个响应者来处理. (即调用super的touches方法),从之前往下走的路线往上回传,在其中加入了Viewtroller来处理
事件不处理,指的是touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
方法不写。
UIButton的继承链是:
UIButton->UIControl->UIView->UIResponder->NSObject
UIApplication能够接受事件,因为UIApplication和UIView一样继承自UIResponder
下面是一个点击事件的方法过程
UIButton *button = [UIButton buttonWithType:UIButtonTypeContactAdd];
button.frame = CGRectMake(100, 100, 40, 40);
[button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];