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 [super hitTest: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不响应用户事件

    return NO;

 

}

时间: 2024-11-08 14:34:31

iOS触摸事件处理--备用的相关文章

iOS触摸事件处理

iOS触摸事件处理 主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景. 一.处理机制 界面响应消息机制分两块,(1)首先在视图的层次结构里找到能响应消息的那个视图.(2)然后在找到的视图里处理消息. [关键](1)的过程是从父View到子View查找,而(2)是从找到的那个子View往父View回溯(不一定会往回传递消息). 1.1.寻找响应消息视图的过程可以借用M了个J的一张图来说明. 处理原理如下: • 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由

ios的hitTest方法以及不规则区域内触摸事件处理方法

ios的hitTest方法以及不规则区域内触摸事件处理方法 概述 在正常的使用场景中,我们处理了比较多的矩形区域内触摸事件,比如UIButton.UIControl.一般来说,这些控件的图形以及触摸区域都是矩形或者圆角矩形的.但是在一些特殊应用场景中我们有时不得不面对这样一种比较严苛的需求,比如要求程序只对某个圆形.五角形等非常规区域的点击事件进行处理,这就需要花点功夫了.本文以圆形为例子来介绍此类场景的处理方法. 先看下面一张图(附图1),我们的目标是实现如下自定义tabbar.中间带突起圆形

IOS开发—事件处理,触摸事件,UITouch,UIEvent,响应者链条,手势识别

触摸事件 在用户使用app过程中,会产生各种各样的事件 一.iOS中的事件可以分为3大类型 触摸事件加速计事件远程控制事件 响应者对象在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为“响应者对象” UIApplication.UIViewController.UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件 二.UIResponder UIResponder内部提供了以下方法来处理事件触摸事件- (v

009-手势触摸事件处理

问题一:iOS中有哪些事件? •在用户使用app过程中,会产生各种各样的事件 •iOS中的事件可以分为3大类型 问题二:什么叫响应者对象? •在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为“响应者对象” •UIApplication.UIViewController.UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件 问题三:UIResponder内部提供了哪些处理事件的方法来处理事件? •UIRes

iOS 的事件处理 响应者链

ios的事件处理时从硬件开始,由驱动传递给系统层面,再传递给应用程序本身(UIApplication),然后会根据响应链找到所谓的firstResponsder,如果它不 进行处理,然后就传递给响应链下一级响应者,直到回到UIApplication(如果响应链上没有响应),由UIApplication进行默认处理. 在代码可控区域内,ios的屏幕点击事件是从上到下(firstResponsder沿着响应联到window再到app本身)的,所以如果点击所在的点不在某个view的区域内,这个view

UITouch 触摸事件处理(转载)

1. UITouch 的主要方法: C代码   - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NS

UIResponder与UIView的触摸事件处理

一.UIResponder UIResponder内部提供了以下方法来处理事件 触摸事件 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void

CocoStudio: 触摸事件处理分析(1)

CocoStudio触摸事件处理: 1. 注册触摸事件处理函数: 方法: /** * Sets the touch event target/selector of the menu item */ void addTouchEventListener(CCObject* target,SEL_TouchEvent selector); 如上面所示,我们看到这里不再像menuItem中那样,针对C++ 和 lua脚本提供了不同的, 这里只考虑lua脚本,不考虑js,因为我对js不熟,也没用过.

总体把握Android中的触摸事件处理

先看几个函数:提到Android的触摸事件处理,不少人都会立刻想到某些令人头疼的函数,这里列举一下,刺激一下你的小神经: @Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(