因?yàn)橹绊?xiàng)目有做超出父VIew的點(diǎn)擊事件,所以記錄一下,以后方便自己鞏固
1.為什么可以觸發(fā)事件
首先看一下UIView,UIVIewController,UIApplication的繼承,都有UIResponder這個(gè)類,大家都叫它響應(yīng)者對象,那為什么繼承它就能接收和處理事件呢?看一下他提供了哪些方法...
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesCancelled:(NSSet<UIPress *> *)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);
這些方法應(yīng)該不是很陌生,分別是觸摸事件,指壓事件(iOS 9 Deep press的相關(guān)方法),加速計(jì)方法(給陀螺儀和加速傳感器使用的方法),遠(yuǎn)程控制(比如耳機(jī)控制)
2.事件產(chǎn)生和傳遞
事件出發(fā)后會(huì)封裝成UIEvent然后放入UIApplication管理的隊(duì)列中(先進(jìn)先出),UIApplication會(huì)從最前面取出事件,將它分發(fā)下去,最先分發(fā)到主窗口(keyWindow),然后主窗口判斷自己是否能接受觸摸事件,觸摸點(diǎn)是否在自己范圍之內(nèi),如果可以的話,在子控件中由后往前遍歷,判斷是否合適,如果合適繼續(xù)遍歷當(dāng)前控件的子控件,如果不合適就是自己本身嘍 ,所以它的傳遞過程是從父控件傳遞給子控件的.
有三個(gè)方法判斷是否接受事件
-
userInteractionEnabled(默認(rèn)view是YES ,表示接受事件) -
alpha透明度 (< 0.01不接受) -
hidden隱藏
3.如何實(shí)現(xiàn)
UIView兩個(gè)重要的方法
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event (有事件傳遞給一個(gè)控件,控件就會(huì)觸發(fā)這個(gè)方法 ,然后通過下面方法判斷是否在范圍內(nèi),返回NO則忽略整個(gè)view)
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
這樣就可以重寫方法上面的方法來實(shí)現(xiàn)一些功能,要想重寫都要自定義View(像擴(kuò)大點(diǎn)擊事件范圍,點(diǎn)擊超過父VIew范圍)
-
寫個(gè)點(diǎn)擊超過父VIew范圍的簡單例子,要重寫父VIew的hitTest方法
黃色是父VIew 加了一個(gè)紅色的子view和UILabel,想要觸發(fā)紅View的點(diǎn)擊事件
#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轉(zhuǎn)換成subview中坐標(biāo)點(diǎn)
// CGPoint newPoint = [subview convertPoint:point toView:self]; subview中point轉(zhuǎn)換成self中坐標(biāo)點(diǎn)
UIView *testHitView = [subview hitTest:newPoint withEvent:event];
if (testHitView) {
return testHitView; //紅色子View
}
}
return nil;
}
2.改變View的觸發(fā)范圍
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event {
//規(guī)則的矩形
return CGRectContainsPoint(newBounds, point); // newBounds為想要的觸發(fā)范圍
//圓形
return pointToCenterDistance < halfRadius; // point到圓心的距離小于半徑
}
以上只是自己的了解,望多多指教
