iOS触摸事件处理--备用
主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景.
一、处理机制
界面响应消息机制分两块,(1)首先在视图的层次结构里找到能响应消息的那个视图。(2)然后在找到的视图里处理消息。
【关键】(1)的过程是从父View到子View查找,而(2)是从找到的那个子View往父View回溯(不一定会往回传递消息)。
1.1、寻找响应消息视图的过程可以借用M了个J的一张图来说明。

处理原理如下:
• 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中
• UIApplication会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件给应用程序的主窗口(UIWindow)
• 主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的UIView来处理触摸事件
(hitTest:withEvent:其实是UIView的一个方法,UIWindow继承自UIView,因此主窗口UIWindow也是属于视图的一种)
• hitTest:withEvent:方法大致处理流程是这样的:
首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:
▶ 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil
▶ 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕:
▷ 若第一次有子视图的hitTest:withEvent:方法返回非空对象,则当前视图的hitTest:withEvent:方法就返回此对象,处理结束
▷ 若所有子视图的hitTest:withEvent:方法都返回nil,则当前视图的hitTest:withEvent:方法返回当前视图自身(self)
• 最终,这个触摸事件交给主窗口的hitTest:withEvent:方法返回的视图对象去处理。
拿到这个UIView后,就调用该UIView的touches系列方法。
1.2、消息处理过程,在找到的那个视图里处理,处理完后根据需要,利用响应链nextResponder可将消息往下一个响应者传递。
UIAppliactionDelegate <- UIWindow <- UIViewController <- UIView <- UIView
【关键】:要理解的有三点:1、iOS判断哪个界面能接受消息是从View层级结构的父View向子View传递,即树状结构的根节点向叶子节点递归传递。2、hitTest和pointInside成对,且hitTest会调用pointInside。3、iOS的消息处理是,当消息被人处理后默认不再向父层传递。
二、应用实例
【需求】是:界面如下,
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。
2.1、需求1的实现,ViewB盖住了ButtonA,所以默认情况下ButtonA收不到消息,但是在消息机制里寻找消息响应是从父View开始,所以我们可以在ViewA的hitTest方法里做判断,若touch point是在ButtonA上,则将ButtonA作为消息处理对象返回。
代码如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | #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[superhitTest:point withEvent:event];    } | 
这样,当触碰点是在ButtonA上时,则touch消息就被拦截在ViewA上,ViewB就收不到了。然后ButtonA就收到touch消息,会触发onClick方法。
2.2、需求2的实现,上面说到响应链,ViewB只要override掉touches系列的方法,然后在自己处理完后,将消息传递给下一个响应者(即父View即ViewA)。
代码如下:在ViewB代码里
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #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上写:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #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透传消息。
2.3 、不让ViewB收到消息,可以设置ViewB.UserInteractionEnable=NO;除了这样还可以override掉ViewB的ponitInside,原理参考上面。
在ViewB上写:
| 1 2 3 4 5 6 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{    // 本View不响应用户事件    returnNO; } | 
iOS触摸事件处理--备用的更多相关文章
- iOS触摸事件处理
		iOS触摸事件处理 主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景. 一.处理机制 界面响应消息机制分两块, (1)首先在视图的层次结构里找到能响应消息的那个视图. (2 ... 
- iOS 触摸事件与手势识别器(Gesture Recognizers)
		Gesture Recognizers与触摸事件分发 通过一个问题引出今天的知识: 1.大家应该都遇见过 当需要给tableView 添加一个tap 手势识别 但是tableView 的上的事件(滑动 ... 
- iOS触摸事件哦
		主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景. 一.处理机制 界面响应消息机制分两块,(1)首先在视图的层次结构里找到能响应消息的那个视图.(2)然后在找到的视图里处理消息 ... 
- IOS触摸事件和手势识别
		IOS触摸事件和手势识别 目录 概述 触摸事件 手势识别 概述 为了实现一些新的需求,我们常常需要给IOS添加触摸事件和手势识别 触摸事件 触摸事件的四种方法 -(void)touchesBegan: ... 
- iOS 触摸的位置放一个大头针
		iOS 触摸的位置放一个大头针 UITapGestureRecognizer *mTap = [[UITapGestureRecognizer alloc] initWithTarget:self a ... 
- cocos2d触摸事件处理机制(2.x和3.x变化)
		2.x的触摸事件的版本号 触摸事件处理有2种子.以下单点触摸的样本.(另一种多点触摸屏). 创建cocos2d 该项目. 1. 重写下面虚函数. bool ccTouchBegan(cocos2d:: ... 
- IOS——触摸事件 视图检测和事件传递
		iPhone上有非常流畅的用户触摸交互体验,能检测各种手势:点击,滑动,放大缩小,旋转.大多数情况都是用UI*GestureRecognizer这样的手势对象来关联手势事件和手势处理函数.也有时候,会 ... 
- IOS 触摸事件分发机制详解
		欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:MelonTeam 前言 很多时候大家都不关心IOS触摸事件的分发机制的实现原理,当遇到以下几种情形的时候你很可能抓破头皮都找不到解决方案 ... 
- IOS (补充)触摸事件处理
		[1]事件的基本概念 UIEvent:事件,是由硬件捕捉的一个表示用户操作设备的对象. 分三类:触摸事件.晃动事件.远程控制事件 触摸事件:用户通过触摸设备屏幕操作对象.输入数据.支持多点触摸,包括1 ... 
随机推荐
- c++ 控制台流和字符串流
			前言 上一章节简单介绍c++中关于流的概念,这两章节将重点讲解如何使用,本章讲解控制台流和字符串流. 控制台输出流 输出流定义在头文件中,使用输出流最简单的方法就是 使用<<运算符.通过你 ... 
- Activity透明/半透明效果的设置transparent(两种实现方法)
			两种方法实现Activity透明/半透明效果的设置,代码思路很有调理,感兴趣的朋友可以参考下,希望本文可以帮助到你 方法一:res/values文件夹下建立styles.xml: 复制代码代码如下 ... 
- 用.class文件创建对象
			第一步: 给你一个编译好的class文件以及它的包名,创建一个对象出来. 1)class文件源代码 package com.wsc.classloader; public class Tool{ p ... 
- tomcat work 目录
			用tomcat作web服务器的时候,部署的程序在webApps下,这些程序都是编译后的程序(发布到tomcat的项目里含的类,会被编译成.class后才发布过来,源文件没有发布过来,但这里的jsp没有 ... 
- Android 布局
			转自:http://www.cnblogs.com/chiao/archive/2011/08/24/2152435.html Android布局是应用界面开发的重要一环,在Android中,共有五种 ... 
- CGLIB学习笔记
			0 概述 CGLIB基于ASM实现.提供比反射更为强大的动态特性.使用CGLIB可以非常方便的实现的动态代理. 0.1 CGLIB包结构 net.sf.cglib.core 底层字节码处理类. ... 
- 树形dp练习
			/*poj 1463 最小点覆盖 匈牙利*/ #include<iostream> #include<cstdio> #include<cstring> #defi ... 
- hadoop之wordCount程序理解
			有篇文章http://www.cnblogs.com/xia520pi/archive/2012/05/16/2504205.html中介绍的 
- ActionScript:Resampling PCM data
			使用基于flash的麦克风录音,如果想在获取完PCM采样数据后,通过Sound马上回放,必须经过resampling.(注意:如果录音是采用的44KHz的话,则不需要) 因此,需要as实现一个简便的函 ... 
- 系统重装c盘后,mysql重新设置
			之前我的mysql装在d盘,重装了系统后,虽然只格式化了c盘,但mysql还是不能用了.我网上找了找.修改了一下配置. 1.首先设置环境变量,编辑path,在后面添加上mysql的安装路径 : 2.之 ... 
