因为之前项目有做超出父VIew的点击事件,所以记录一下,以后方便自己巩固
1.为什么可以触发事件
首先看一下UIView
,UIVIewController
,UIApplication
的继承,都有UIResponder这个类,大家都叫它响应者对象,那为什么继承它就能接收和处理事件呢?看一下他提供了哪些方法...
- (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet *)touches NS_AVAILABLE_IOS(9_1);
- (void)pressesBegan:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesChanged:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesEnded:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesCancelled:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)remoteControlReceivedWithEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(4_0);
这些方法应该不是很陌生,分别是触摸事件,指压事件(iOS 9 Deep press的相关方法),加速计方法(给陀螺仪和加速传感器使用的方法),远程控制(比如耳机控制)
2.事件产生和传递
事件出发后会封装成UIEvent
然后放入UIApplication
管理的队列中(先进先出),UIApplication
会从最前面取出事件,将它分发下去,最先分发到主窗口(keyWindow),然后主窗口判断自己是否能接受触摸事件,触摸点是否在自己范围之内,如果可以的话,在子控件中由后往前遍历,判断是否合适,如果合适继续遍历当前控件的子控件,如果不合适就是自己本身喽 ,所以它的传递过程是从父控件传递给子控件的.
有三个方法判断是否接受事件
-
userInteractionEnabled
(默认view是YES ,表示接受事件) -
alpha
透明度 (< 0.01不接受) -
hidden
隐藏
3.如何实现
UIView
两个重要的方法
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
(有事件传递给一个控件,控件就会触发这个方法 ,然后通过下面方法判断是否在范围内,返回NO则忽略整个view)
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
这样就可以重写方法上面的方法来实现一些功能,要想重写都要自定义View(像扩大点击事件范围,点击超过父VIew范围)
-
写个点击超过父VIew范围的简单例子,要重写父VIew的hitTest方法
#import "YellowView.h"
@implementation YellowView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor yellowColor];
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(0, -60, 50, 50)];
redView.backgroundColor = [UIColor redColor];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapaction)];
[redView addGestureRecognizer:tap];
[self addSubview:redView];
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(-60, 10, 50, 30)];
lbl.font = [UIFont systemFontOfSize:13];
lbl.text = @"看得出来";
[self addSubview:lbl];
}
return self;
}
-(void)tapaction{
NSLog(@"我是姨妈红");
}
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
if (!self.userInteractionEnabled || self.isHidden == YES || self.alpha <= 0.01) {
return nil;
}
for (UIView *subview in [self.subviews reverseObjectEnumerator]) { //倒序遍历
CGPoint newPoint = [subview convertPoint:point fromView:self]; //self中point转换成subview中坐标点
// CGPoint newPoint = [subview convertPoint:point toView:self]; subview中point转换成self中坐标点
UIView *testHitView = [subview hitTest:newPoint withEvent:event];
if (testHitView) {
return testHitView; //红色子View
}
}
return nil;
}
2.改变View的触发范围
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event {
//规则的矩形
return CGRectContainsPoint(newBounds, point); // newBounds为想要的触发范围
//圆形
return pointToCenterDistance < halfRadius; // point到圆心的距离小于半径
}
以上只是自己的了解,望多多指教