广

IOS开发

  • IOS开发
  • android开发
  • PHP编程
  • JavaScript
  • ASP.NET
  • ASP编程
  • JSP编程
  • Java编程
  • 易语言
  • Ruby编程
  • Perl编程
  • AJAX
  • 正则表达式
  • C语言
  • 编程开发

    举例讲解iOS应用开发中hitTest触摸事件的编写方法

    2018-04-06 10:41:20 次阅读 稿源:互联网
    零七广告

     hitTest:withEvet  调用过程

    比如如果是当前的View A, 还有一个viewB

    如果不重写 hitTest 方法,那么 系统默认是先调用viewA的hitest 方法,然后再调用viewB的htest方法。

    系统的调用过程,跟下面的重写hitest的方法是一模一样的。
    代码如下:

    -(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

        if ([self pointInside:point withEvent:event]) { 
        } 
        else { 
            return nil; 
        } 
        for (UIView *subView in self.subviews) { 
            if ([subView hitTest:point withEvent:event]!=nil) { 
                return subView; 
            } 
        } 
         
        return self; 


    在说明一次,如果不重写hitest方法,那么每一个UIVIeew的默认hitest的方法都是上面这个处理流程。

    那也没啥好说的。

    但是对于一些特殊的处理过程,就不行了

    所以之所以重写hitTest方法,通常都是为了穿透上层 的 UIview,让touch事件可以达到下面的uiview,

    比如 view A  和 VIew B,

    View b完全挡住了view A,但是我想让点击viewB的时候,view A可以响应点击的事件。就可以采用下面的方法:
    代码如下:

    -(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

        if ([self pointInside:point withEvent:event]) { 
            NSLog(@"in view A"); 
            return self; 
        } 
        else { 
            return nil; 
        } 
     

    深入
    我们来更深入一下,现在有个实例需求界面如下,

    Window

      -ViewA

        -ButtonA

        -ViewB

          -ButtonB

    层次结构:ViewB完全盖住了ButtonA,ButtonB在ViewB上,现在需要实现:
    (1)ButtonA和ButtonB都能响应消息 (2)ViewA也能收到ViewB所收到的touches消息 (3)不让ViewB(ButtonB)收到消息。

    (首先解析下,默认情况下,点击了ButtonB的区域,iOS消息处理过程。

    -ViewA

      -ButtonA

      -ViewB

        -ButtonB

    当点击ButtonB区域后,处理过程:从ViewA开始依次调用hitTest

    pointInside的值依次为:

    ViewA:NO;

    ViewB:YES;

    ButtonB:YES;

    ButtonB的subViews:NO;

    所以ButtonB的subViews的hitTest都返回nil,于是返回的处理对象是ButtonB自己。接下去开始处理touches系列方法,这里是调用ButtonB绑定的方法。处理完后消息就停止,整个过程结束。)

    分析:

    实现的方式多种,这里将两个需求拆解开来实现,因为实现2就可以满足1。

    需求1的实现,ViewB盖住了ButtonA,所以默认情况下ButtonA收不到消息,但是在消息机制里寻找消息响应是从父View开始,所以我们可以在ViewA的hitTest方法里做判断,若touch point是在ButtonA上,则将ButtonA作为消息处理对象返回。

    代码如下:
    代码如下:

    #pragma mark - hitTest
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        // 当touch point是在_btn上,则hitTest返回_btn
        CGPoint btnPointInA = [_btn convertPoint:point fromView:self];
        if ([_btn pointInside:btnPointInA withEvent:event]) {
            return _btn;
        }
        
        // 否则,返回默认处理
        return [super hitTest:point withEvent:event];
        
    }

    这样,当触碰点是在ButtonA上时,则touch消息就被拦截在ViewA上,ViewB就收不到了。然后ButtonA就收到touch消息,会触发onClick方法。

    需求2的实现,上面说到响应链,ViewB只要override掉touches系列的方法,然后在自己处理完后,将消息传递给下一个响应者(即父View即ViewA)。

    代码如下:在ViewB代码里
    代码如下:

    #pragma mark - touches
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"B - touchesBeagan..");
        
        // 把事件传递下去给父View或包含他的ViewController
        [self.nextResponder touchesBegan:touches withEvent:event];
    }
     
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"B - touchesCancelled..");
        // 把事件传递下去给父View或包含他的ViewController
        [self.nextResponder touchesBegan:touches withEvent:event];
    }
     
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"B - touchesEnded..");
        // 把事件传递下去给父View或包含他的ViewController
        [self.nextResponder touchesBegan:touches withEvent:event];
    }
     
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"B - touchesMoved..");
        // 把事件传递下去给父View或包含他的ViewController
        [self.nextResponder touchesBegan:touches withEvent:event];
        
    }

    然后,在ViewA上就可以接收到touches消息,在ViewA上写:
    代码如下:

    #pragma mark - touches
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"A - touchesBeagan..");
    }
     
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"A - touchesCancelled..");
    }
     
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"A - touchesEnded..");
    }
     
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"A - touchesMoved..");
        
    }

    这样就实现了向父View透传消息。

    不让ViewB收到消息,可以设置ViewB.UserInteractionEnable=NO;除了这样还可以override掉ViewB的ponitInside,原理参考上面。

    在ViewB上写:
    代码如下:

    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
        // 本View不响应用户事件
        return NO;
     
    }

    零七网部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与零七网进行文章共享合作。

    零七广告
    零七广告
    零七广告
    零七广告