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

 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;
 
}

时间: 2024-08-04 10:23:29

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

举例讲解iOS应用开发中对设计模式中的策略模式的使用_IOS

策略模式是一种常见的软件设计模式,这里简单得介绍一下策略模式并用IOS简单实现一下. 所谓的策略模式,顾名思义是要采用不同的策略的.一般来说,在不同的情况下,处理某一个问题的方法也不一样.比如说对字符串的排序和对数字的排序,虽然用的都是快排,但是显然不可能使用一段通用的代码.有人说java里面的compareTo可以做到,但如果考虑这么一个问题:同样是出门旅行,老年人身体虚弱,需要大量的休息,而孩子则是精力充沛,希望玩到更多的景点.如何在同一模式下表达以上信息.采用合理的设计模式进行封装而不是大

简单讲解iOS应用开发中的MD5加密的相关使用_IOS

一.简单说明 1.说明 在开发应用的时候,数据的安全性至关重要,而仅仅用POST请求提交用户的隐私数据,还是不能完全解决安全问题. 如:可以利用软件(比如Charles)设置代理服务器,拦截查看手机的请求数据 "青花瓷"软件 因此:提交用户的隐私数据时,一定不要明文提交,要加密处理后再提交   2.常见的加密算法 MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ RSA \ IDEA \ DSA \ AES 3.加密算法的选择 一般公司都会有一套自己的加密方案,按照

举例讲解Android应用开发中OTTO框架的基本使用_Android

OTTO是一个EventBus类型的事件传输总线,它可以提供"存储转发"的功能,让你APP中各个组件的交流更加便利,让你的程序分层更加清晰. 使用场景OTTO基于Observer设计模式.它有发布者,订阅者这两个主要对象.OTTO的最佳实践就是通过反射牺牲了微小的性能,同时极大的提高了程序的耦合度,更加利于MVP分工开发与维护.业务层开发者在处理资源(比如Db, REST等)后并发布消息,展示层开发者(比如Activity/Fragment)就可以处理消息,而不用关心数据是怎么来的(在

举例讲解Android应用开发中OTTO框架的基本使用

OTTO是一个EventBus类型的事件传输总线,它可以提供"存储转发"的功能,让你APP中各个组件的交流更加便利,让你的程序分层更加清晰. 使用场景 OTTO基于Observer设计模式.它有发布者,订阅者这两个主要对象.OTTO的最佳实践就是通过反射牺牲了微小的性能,同时极大的提高了程序的耦合度,更加利于MVP分工开发与维护.业务层开发者在处理资源(比如Db, REST等)后并发布消息,展示层开发者(比如Activity/Fragment)就可以处理消息,而不用关心数据是怎么来的(

iOS App开发中使用及自定义UITableViewCell的教程_IOS

UITableView用来以表格的形式显示数据.关于UITableView,我们应该注意: (1)UITableView用来显示表格的可见部分,UITableViewCell用来显示表格的一行. (2)UITableView并不负责存储表格中的数据,而是仅仅存储足够的数据使得可以画出当前可见部分. (3)UITableView从UITableViewDelegate协议获取配置信息,从UITableViewDataSource协议获得数据信息. (4)所有的UITableView实现时实际上只有

jQuery移动页面开发中的触摸事件与虚拟鼠标事件简介_jquery

触摸事件(touch)在 jQuery Mobile 中有一些触摸事件是可定制的.然而,这些事件仅当与支持触摸功能的设备进行交互的用户访问您的 jQuery Mobile 网站时才可用.当这些事件可用时,您可以触发任何自定义java script 作为对五种不同的事件的响应tap.taphold.swipe.swipeleft 和 swiperight. tap(轻击):一次快速完整的轻击后触发 taphold(轻击不放):轻击并不放(大约一秒)后触发 swipe(滑动):一秒内水平拖拽大于30

javascript移动开发中touch触摸事件详解_javascript技巧

事件对象是用来记录一些事件发生时的相关信息的对象.事件对象只有事件发生时才会产生,并且只能是事件处理函数内部访问,在所有事件处理函数运行结束后,事件对象就被销毁! W3C DOM把事件对象作为事件处理函数的第一个参数传入进去 IE将事件对象作为window对象的一个属性(相当于全局变量) originalEvent对象 在一次偶然的使用中,我发现当使用on()函数并且传入第二个选择器参数时,e.touches[0]的访问为undefined,打印e发现,它的事件对象不是原生的事件对象.经查阅发现

iOS App开发中UITextField组件的常用属性小结_IOS

重点属性 在 Xcode 中使用 IB 给视图拖上去一个文本框后,选中文本框,可以在Attribute Inspector中设置其各种属性. Attribute Inspector 分为三部分,分别是 Text Field.Control 和 View 部分.我们重点看看 Text Field 部分. Text Field 部分有以下选项: 1.Text :设置文本框的默认文本. 2.Placeholder : 可以在文本框中显示灰色的字,用于提示用户应该在这个文本框输入什么内容.当这个文本框中

实例讲解iOS应用开发中使用UITableView创建自定义表格_IOS

一.带索引目录的表视图 1.效果图 2.数据源 本想获取通讯录中得名字,但为了用模拟器调试方便,就写死了数据,所以也只写了部分字母,总之有那么点意思就成 复制代码 代码如下: @interface ViewController ()<UITableViewDataSource,UITableViewDelegate> {     NSArray *sectionTitles; // 每个分区的标题     NSArray *contentsArray; // 每行的内容 } /** @brie