iOS-事件的hitTest處理

因?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è)方法判斷是否接受事件

  1. userInteractionEnabled (默認(rèn)view是YES ,表示接受事件)
  2. alpha 透明度 (< 0.01不接受)
  3. 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范圍)

  1. 寫個(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到圓心的距離小于半徑
}

以上只是自己的了解,望多多指教

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容